Cakupan variabel Xamarin XAML tidak berfungsi seperti yang diharapkan

Saya memiliki masalah yang sangat aneh dengan cakupan variabel. Tampilan Daftar bernama "TodoListView" ditentukan melalui xaml, dan ItemSource diisi dari database SQListe. Bekerja. Di dalam ListView saya memiliki ViewCell untuk menampilkan data berdasarkan baris.

<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);
        }
    }
}

}

Keanehannya memiliki dua tahap. Sebelum saya memasukkan event handler DoneSwitchToggled, setiap kemunculan TodoListView.ItemsSource mendapat garis bawah merah di bawah TodoListView dan petunjuk bahwa "Nama TodoListView tidak ada dalam konteks saat ini". Oke, saya pikir VS tidak cukup pintar untuk menemukan definisi di file xaml, karena meskipun ada peringatan, program dikompilasi dan berjalan dengan baik. TodoListView diinisialisasi dan menampilkan baris database yang mendasarinya dengan benar, sehingga jelas ada saat runtime.

Segalanya menjadi liar ketika saya menambahkan event handler DoneSwitchToggled ke XAML dan kode di belakang. Tiba-tiba program tidak dapat dikompilasi lagi tetapi keluar dengan kesalahan CS0103 "Nama" TodoListView "tidak ada dalam konteks saat ini". Kesalahan muncul tiga kali, dengan nomor baris menunjuk ke kemunculan TodoListView lainnya di onAppearing() dan OnReloadButtonClicked(). Hah? Bagaimana penambahan referensi variabel di event handler membuat variabel itu tidak valid dalam metode yang sama sekali berbeda? Oke, ada yang mencurigakan dengan variabel sebelumnya (masih belum tahu apa...), tapi berhasil. Sekarang tidak ada lagi, yang tidak masuk akal bagi saya. Selanjutnya, jika saya mengomentari baris yang menyinggung di event handler DoneSwitchToggled, dan memasukkan definisi dummy untuk i, seperti:

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

semuanya seperti sebelumnya, VS masih menggarisbawahi tampilan TodoListView lainnya, tetapi sekarang program dibangun dan berjalan dengan baik kembali.

Adakah yang bisa menjelaskan efek ini, dan menunjukkan seberapa benar kode saya? Saya pikir tujuannya jelas: DoneSwitchToggled seharusnya menulis kembali nilai saklar ke dalam database (dan melakukan beberapa pemrosesan lain yang tidak ditampilkan dalam sampel saya), dan meskipun objek "pengirim" disetel dengan benar untuk mereferensikan tombol saya, saya tidak menemukan cara untuk mengakses pengikatan data yang mendasarinya, karena sayangnya ToggledEventArgs tampaknya hanya meneruskan posisi sakelar "benar" atau "salah", tetapi - tidak seperti pengendali peristiwa OnListItemSelected - tidak meneruskan referensi apa pun ke baris terikat melalui argumen kedua. Jadi ide saya adalah menggunakan ListView.SelectedItem untuk tujuan ini.


person Nimral    schedule 28.02.2018    source sumber
comment
Setelah beberapa pengujian, ini seharusnya benar-benar berfungsi, coba bersihkan semuanya dari proyek yang bukan kode Anda dan bangun kembali.   -  person Ivan Ičin    schedule 28.02.2018


Jawaban (1)


Akhirnya saya menemukan jawabannya sendiri. Tampaknya ini adalah kesalahan di VS 2017. Tidak ada yang salah dengan TodoListView, jadi kesalahan CS0103 adalah omong kosong yang menyesatkan.

Yang dimaksud VS sebenarnya adalah error CS0266. TodoListView ditentukan oleh daftar umum

List<TodoItem>

untuk mengakses SelectedItem saya perlu mengetikkannya:

TodoItem i = (TodoItem)TodoListView.SelectedItem;

Ini ditambahkan, semua kesalahan hilang, kode aplikasi dibuat dengan baik.

Ngomong-ngomong, sayangnya pendekatan untuk mendapatkan item di mana Switch telah dibalik terbukti tidak berfungsi, TodoListView selalu mengembalikan null untuk SelectedItem, sepertinya kontrol ListView tidak melihat tombol ditekan. Perlu menemukan cara lain untuk menemukan item daftar di bawah sakelar untuk mendapatkan id baris terikat.

person Nimral    schedule 28.02.2018