ObservableObject

ObservableObject adalah kelas dasar untuk objek yang dapat diamati dengan mengimplementasikan INotifyPropertyChanged antarmuka dan INotifyPropertyChanging . Ini dapat digunakan sebagai titik awal untuk semua jenis objek yang perlu mendukung pemberitahuan perubahan properti.

API Platform:ObservableObject, TaskNotifier, TaskNotifier<T>

Cara kerjanya

ObservableObject memiliki fitur utama berikut:

  • Ini menyediakan implementasi dasar untuk INotifyPropertyChanged dan INotifyPropertyChanging, mengekspos PropertyChanged peristiwa dan PropertyChanging .
  • Ini menyediakan serangkaian SetProperty metode yang dapat digunakan untuk dengan mudah mengatur nilai properti dari jenis yang diwarisi dari ObservableObject, dan untuk secara otomatis meningkatkan peristiwa yang sesuai.
  • Ini menyediakan SetPropertyAndNotifyOnCompletion metode , yang dianalogikan tetapi SetProperty dengan kemampuan untuk mengatur Task properti dan menaikkan peristiwa pemberitahuan secara otomatis ketika tugas yang ditetapkan selesai.
  • Ini mengekspos OnPropertyChanged metode dan OnPropertyChanging , yang dapat ditimpa dalam jenis turunan untuk menyesuaikan bagaimana peristiwa pemberitahuan dinaikkan.

Properti sederhana

Berikut adalah contoh cara menerapkan dukungan pemberitahuan ke properti kustom:

public class User : ObservableObject
{
    private string name;

    public string Name
    {
        get => name;
        set => SetProperty(ref name, value);
    }
}

Metode yang disediakan SetProperty<T>(ref T, T, string) memeriksa nilai properti saat ini, dan memperbaruinya jika berbeda, lalu juga menaikkan peristiwa yang relevan secara otomatis. Nama properti secara otomatis diambil melalui penggunaan [CallerMemberName] atribut, jadi tidak perlu menentukan properti mana yang sedang diperbarui secara manual.

Membungkus model yang tidak dapat diamati

Skenario umum, misalnya, saat bekerja dengan item database, adalah membuat model "dapat diikat" pembungkusan yang menyampaikan properti model database, dan menaikkan pemberitahuan yang diubah properti saat diperlukan. Ini juga diperlukan ketika ingin menyuntikkan dukungan pemberitahuan ke model, yang tidak mengimplementasikan INotifyPropertyChanged antarmuka. ObservableObject menyediakan metode khusus untuk membuat proses ini lebih sederhana. Untuk contoh berikut, User adalah model yang langsung memetakan tabel database, tanpa mewarisi dari ObservableObject:

public class ObservableUser : ObservableObject
{
    private readonly User user;

    public ObservableUser(User user) => this.user = user;

    public string Name
    {
        get => user.Name;
        set => SetProperty(user.Name, value, user, (u, n) => u.Name = n);
    }
}

Dalam hal ini kita menggunakan SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) kelebihan beban. Tanda tangan sedikit lebih kompleks daripada yang sebelumnya - ini perlu untuk membiarkan kode masih sangat efisien bahkan jika kita tidak memiliki akses ke bidang dukungan seperti dalam skenario sebelumnya. Kita dapat melalui setiap bagian dari tanda tangan metode ini secara rinci untuk memahami peran komponen yang berbeda:

  • TModel adalah argumen jenis, menunjukkan jenis model yang kita bungkus. Dalam hal ini, itu akan menjadi kelas kita User . Perhatikan bahwa kita tidak perlu menentukan ini secara eksplisit - pengkompilasi C# akan menyimpulkan ini secara otomatis dengan cara kita memanggil metode .SetProperty
  • T adalah jenis properti yang ingin kita tetapkan. Demikian TModelpula dengan , ini disimpulkan secara otomatis.
  • T oldValue adalah parameter pertama, dan dalam hal ini kita menggunakan user.Name untuk meneruskan nilai saat ini dari properti yang sedang kita bungkus.
  • T newValue adalah nilai baru untuk diatur ke properti, dan di sini kita meneruskan value, yang merupakan nilai input dalam setter properti.
  • TModel model adalah model target yang kita bungkus, dalam hal ini kita meneruskan instans yang disimpan di user bidang .
  • Action<TModel, T> callback adalah fungsi yang akan dipanggil jika nilai baru properti berbeda dari yang saat ini, dan properti perlu diatur. Ini akan dilakukan oleh fungsi panggilan balik ini, yang menerima sebagai input model target dan nilai properti baru yang akan ditetapkan. Dalam hal ini kami hanya menetapkan nilai input (yang kami panggil n) ke Name properti (dengan melakukan u.Name = n). Penting di sini untuk menghindari pengambilan nilai dari cakupan saat ini dan hanya berinteraksi dengan yang diberikan sebagai input ke panggilan balik, karena ini memungkinkan pengkompilasi C# untuk menyimpan fungsi panggilan balik dan melakukan sejumlah peningkatan performa. Karena inilah kita tidak hanya langsung mengakses user bidang di sini atau value parameter di setter, tetapi sebaliknya kita hanya menggunakan parameter input untuk ekspresi lambda.

Metode ini SetProperty<TModel, T>(T, T, TModel, Action<TModel, T>, string) membuat pembuatan properti pembungkusan ini sangat sederhana, karena mengurus pengambilan dan pengaturan properti target sambil menyediakan API yang sangat ringkas.

Catatan

Dibandingkan dengan implementasi metode ini menggunakan ekspresi LINQ, khususnya melalui parameter jenis Expression<Func<T>> alih-alih parameter status dan panggilan balik, peningkatan performa yang dapat dicapai dengan cara ini benar-benar signifikan. Secara khusus, versi ini ~ 200x lebih cepat daripada yang menggunakan ekspresi LINQ, dan tidak membuat alokasi memori sama sekali.

Menangani Task<T> properti

Jika properti adalah Task penting untuk juga menaikkan peristiwa pemberitahuan setelah tugas selesai, sehingga pengikatan diperbarui pada waktu yang tepat. misalnya untuk menampilkan indikator pemuatan atau info status lainnya pada operasi yang diwakili oleh tugas. ObservableObject memiliki API untuk skenario ini:

public class MyModel : ObservableObject
{
    private TaskNotifier<int>? requestTask;

    public Task<int>? RequestTask
    {
        get => requestTask;
        set => SetPropertyAndNotifyOnCompletion(ref requestTask, value);
    }

    public void RequestValue()
    {
        RequestTask = WebService.LoadMyValueAsync();
    }
}

SetPropertyAndNotifyOnCompletion<T>(ref TaskNotifier<T>, Task<T>, string) Di sini metode akan mengurus pembaruan bidang target, memantau tugas baru, jika ada, dan menaikkan peristiwa pemberitahuan ketika tugas tersebut selesai. Dengan cara ini, dimungkinkan untuk hanya mengikat ke properti tugas dan diberi tahu ketika statusnya berubah. TaskNotifier<T> adalah jenis khusus yang diekspos oleh ObservableObject yang membungkus instans target Task<T> dan memungkinkan logika pemberitahuan yang diperlukan untuk metode ini. Jenis TaskNotifier ini juga tersedia untuk digunakan secara langsung jika Anda hanya memiliki umum Task .

Catatan

Metode SetPropertyAndNotifyOnCompletion ini dimaksudkan untuk mengganti penggunaan jenis NotifyTaskCompletion<T> dari Microsoft.Toolkit paket. Jika jenis ini sedang digunakan, jenis ini dapat diganti hanya dengan properti dalam Task (atau Task<TResult>) , dan kemudian SetPropertyAndNotifyOnCompletion metode dapat digunakan untuk mengatur nilainya dan menaikkan perubahan pemberitahuan. Semua properti yang diekspos oleh NotifyTaskCompletion<T> jenis tersedia langsung pada Task instans.

Contoh