前往
大廳
主題

WPF實作INotifyPropertyChanged

Yang | 2022-06-30 08:26:33 | 巴幣 0 | 人氣 362

介面INotifyPropertyChanged
微軟的WPF框架,要讓表格(DataGrid)能呈現資料表,能即時呈現資料異動,資料結構必須先繼承和實作INotifyPropertyChanged,再儲存到ObservableCollection<T>內,ObservableCollection<T>再繫節(Binding)到DataGrid.ItemsSource

為了讓資料結構能序列化(Serializable),能利用ORMap工具(譬如Dapper)直接對應到DB的DataTable,能直接序列化儲存到檔案或是透過網路傳輸,實作INotifyPropertyChanged時有些眉角要注意([field: NonSerialized()]),否則序列化時會跳錯(SerializationException)

參考資料

這裡先記錄資料結構的基底類別NotifyPropertyChanged

[Serializable]
public class NotifyPropertyChanged : INotifyPropertyChanged
{
    /// <summary>
    /// 事件通知指定欄位有資料變更
    /// </summary>
    [field: NonSerialized()]
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        PropertyChanged?.Invoke(this, e);
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="propertyName">欄位名稱</param>
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    /// <summary>
    /// 有一個欄位可能有資料異動
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="field">舊資料</param>
    /// <param name="value">新資料</param>
    /// <param name="propertyName">欄位名稱</param>
    /// <returns>是否有異動</returns>
    protected virtual bool OnPropertyChanged<T>(ref T field, T value, [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
        {
            return false;
        }

        field = value;
        OnPropertyChanged(propertyName);

        return true;
    }

    /// <summary>
    /// 有多個欄位可能有資料異動
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="field">舊資料</param>
    /// <param name="value">新資料</param>
    /// <param name="propertyName">第一個欄位名稱</param>
    /// <param name="otherNames">其它欄位名稱</param>
    /// <returns>是否有異動</returns>
    protected virtual bool OnPropertiesChanged<T>(ref T field, T value, string propertyName, params string[] otherNames)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
        {
            return false;
        }

        field = value;
        OnPropertyChanged(propertyName);

        foreach (string name in otherNames)
        {
            OnPropertyChanged(name);
        }

        return true;
    }
}

寫C/C++的人看到new PropertyChangedEventArgs(propertyName)大概會覺得渾身不舒服,每次變更資料都要new一個PropertyChangedEventArgs物件,記憶體使用上的規劃和效能的損耗會覺得很恐怖

實際測試是看不出CPU或記憶體飆高的情況,耗時也測不出來(< 1 ms),應該是.NET有很好的記憶體管理機制(garbage collection)

DataGrid和ObservableCollection<T>相關程式碼之後再補充
送禮物贊助創作者 !
0
留言

創作回應

更多創作