ขอบเขตตัวแปร Xamarin XAML ไม่ทำงานอย่างที่คาดไว้

ฉันมีปัญหาแปลก ๆ กับขอบเขตตัวแปร Listview ชื่อ "TodoListView" ถูกกำหนดผ่าน xaml และเป็น ItemSource ที่เติมจากฐานข้อมูล SQListe ได้ผล ภายใน ListView ฉันมี ViewCell เพื่อแสดงข้อมูลตามแถว

<ContentPage ... x:Class="JanitorPro.MainPage" ...>
  <StackLayout>
        <ListView x:Name="TodoListView" Margin="20" ItemSelected="OnListItemSelected">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
                            <Label Text="{Binding name}" VerticalTextAlignment="Center" HorizontalOptions="StartAndExpand" />
                            <Switch HorizontalOptions="End" IsToggled="{Binding done}" Toggled="DoneSwitchToggled"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>

The codebehind looks like this (some irrelevant portions removed):

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();

        // load Database
        TodoListView.ItemsSource = await App.TodoDatabase.GetItemsAsync("SELECT * FROM [TodoItem]");
    }

    async void OnReloadButtonClicked(object sender, EventArgs e)
    {
        Debug.WriteLine("Reload Button Click");
        TodoListView.ItemsSource = await App.TodoDatabase.GetItemsAsync("SELECT * FROM [TodoItem]");
            Debug.WriteLine("Reload done.");
    }


    async void OnListItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        if (e.SelectedItem != null)
        {
            await Navigation.PushAsync(new TodoItemPage
            {
                BindingContext = e.SelectedItem as TodoItem
            });
        }
    }

    private void DoneSwitchToggled(object sender, ToggledEventArgs e)
    {
        // TodoItem i = null; 
        TodoItem i = TodoListView.SelectedItem;
        if (i != null)
        {
            Debug.WriteLine("Toggle: {0}", i.id);
        }
    }
}

}

ความแปลกประหลาดมีสองขั้นตอน ก่อนที่ฉันจะแทรกตัวจัดการเหตุการณ์ DoneSwitchToggled ทุกเหตุการณ์ของ TodoListView.ItemsSource ได้รับการขีดเส้นใต้สีแดงภายใต้ TodoListView และคำใบ้ว่า "ชื่อ TodoListView ไม่มีอยู่ในบริบทปัจจุบัน" โอเค ฉันคิดว่า VS ไม่ฉลาดพอที่จะค้นหาคำจำกัดความในไฟล์ xaml เพราะถึงแม้จะมีคำเตือน โปรแกรมก็คอมไพล์และทำงานได้ดี TodoListView ได้รับการเตรียมใช้งานและแสดงแถวของฐานข้อมูลที่เกี่ยวข้องอย่างถูกต้อง ดังนั้นจึงมีอยู่อย่างชัดเจนในขณะรันไทม์

สิ่งต่าง ๆ เกิดขึ้นอย่างรวดเร็วเมื่อฉันเพิ่มตัวจัดการเหตุการณ์ DoneSwitchToggled ให้กับทั้ง XAML และโค้ดด้านหลัง ทันใดนั้นโปรแกรมจะไม่คอมไพล์อีกต่อไป แต่ประกันตัวด้วยข้อผิดพลาด CS0103 "ชื่อ "TodoListView" ไม่มีอยู่ในบริบทปัจจุบัน" ข้อผิดพลาดปรากฏขึ้นสามครั้ง โดยหมายเลขบรรทัดชี้ไปที่เหตุการณ์อื่นๆ ของ TodoListView ใน onAppearing() และ OnReloadButtonClicked() ฮะ? การเพิ่มการอ้างอิงตัวแปรในตัวจัดการเหตุการณ์ทำให้ตัวแปรนั้นไม่ถูกต้องในวิธีที่ต่างกันโดยสิ้นเชิงได้อย่างไร ตกลง ก่อนหน้านี้มีบางสิ่งที่คาวกับตัวแปร (ยังไม่รู้ว่าอะไร ... ) แต่มันก็ได้ผล ตอนนี้มันไม่มีอีกแล้ว ซึ่งมันไม่สมเหตุสมผลสำหรับฉัน นอกจากนี้ หากฉันใส่ความคิดเห็นเกี่ยวกับบรรทัดที่ละเมิดในตัวจัดการเหตุการณ์ DoneSwitchToggled และใส่คำจำกัดความจำลองสำหรับ i ดังนี้:

        TodoItem i = null; 
        // TodoItem i = TodoListView.SelectedItem;

ทุกอย่างเหมือนเดิม VS ยังคงเน้นย้ำลักษณะที่ปรากฏอื่นๆ ของ TodoListView แต่ตอนนี้โปรแกรมสร้างและทำงานได้อีกครั้ง

ใครก็ตามที่สามารถอธิบายผลกระทบนี้ และแสดงให้ฉันเห็นว่ารหัสของฉันถูกต้องอย่างไร ฉันคิดว่าวัตถุประสงค์นั้นชัดเจน: DoneSwitchToggled ควรจะเขียนกลับค่าสวิตช์ลงในฐานข้อมูล (และทำการประมวลผลอื่น ๆ ที่ไม่แสดงในตัวอย่างที่แยกออกมาของฉัน) และแม้ว่าวัตถุ "ผู้ส่ง" จะได้รับการตั้งค่าอย่างถูกต้องเพื่ออ้างอิงปุ่มของฉัน แต่ฉัน ไม่พบวิธีเข้าถึงการเชื่อมโยงข้อมูลพื้นฐาน เนื่องจาก ToggledEventArgs ดูเหมือนจะผ่านตำแหน่งสวิตช์ "จริง" หรือ "เท็จ" เท่านั้น แต่ - ไม่เหมือนกับตัวจัดการเหตุการณ์ OnListItemSelected - ไม่ผ่านการอ้างอิงใด ๆ ไปยังแถวที่ถูกผูกไว้ผ่านอาร์กิวเมนต์ที่สอง ดังนั้นความคิดของฉันคือใช้ ListView.SelectedItem เพื่อจุดประสงค์นี้


person Nimral    schedule 28.02.2018    source แหล่งที่มา
comment
หลังจากการทดสอบบางอย่าง สิ่งนี้น่าจะได้ผลจริง ลองล้างทุกอย่างออกจากโปรเจ็กต์ที่ไม่ใช่โค้ดของคุณ แล้วสร้างใหม่   -  person Ivan Ičin    schedule 28.02.2018


คำตอบ (1)


ในที่สุดฉันก็คิดออกเอง นี่ดูเหมือนจะเป็นความผิดพลาดใน VS 2017 TodoListView ไม่มีอะไรผิดปกติ ดังนั้นข้อผิดพลาด CS0103 จึงเป็นเรื่องไร้สาระที่ทำให้เข้าใจผิด

สิ่งที่ VS หมายถึงจริง ๆ คือข้อผิดพลาด CS0266 TodoListView ถูกกำหนดโดยรายการทั่วไป

List<TodoItem>

เพื่อเข้าถึง SelectedItem ฉันต้องพิมพ์มัน:

TodoItem i = (TodoItem)TodoListView.SelectedItem;

ที่เพิ่มเข้ามานี้ ข้อผิดพลาดทั้งหมดหายไปแล้ว โค้ดของแอปสร้างได้ตามปกติ

น่าเสียดายที่วิธีการนี้ในการไปที่รายการที่มีการพลิกสวิตช์ได้รับการพิสูจน์แล้วว่าไม่ทำงาน TodoListView จะคืนค่า null สำหรับ SelectedItem เสมอ ดูเหมือนว่าตัวควบคุม ListView จะไม่เห็นการกดปุ่ม จำเป็นต้องหาวิธีอื่นในการค้นหารายการใต้สวิตช์เพื่อให้ได้รหัสแถวที่ถูกผูกไว้

person Nimral    schedule 28.02.2018