[WPF學習筆記] - 嵌套屬性的數據刷新方式探索

場景

在WPF中,使用屬性Binding到UI自動刷新是常用的手段。平時除了使用普通屬性,如public string Value {get; set;},還會用到嵌套屬性(不知道這個名稱對不對),類似這樣的形式public string Value => _m.Value;。這時候數據刷新就會碰到一定的問題。

準備工作

已知類NotifyPropertyChangedHelper,只需繼承NotifyPropertyChangedHelper,即可在需要刷新屬性時調用OnPropertyChanged()即可,該方法會自動反射調用該方法的屬性名,等價於自動獲取nameof(xxx)

public class NotifyPropertyChangedHelper : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// 通知屬性更改
    /// 默認通知方法所在屬性
    /// </summary>
    /// <param name="propertyName"></param>
    public void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
    {
        PropertyChanged?.Invoke(this, eventArgs);
    }
}

若是想代碼更簡潔,可以安裝Fody與PropertyChanged.Fody兩個包。則連上面的OnPropertyChanged方法也省略不寫了。
在這裏插入圖片描述

測試界面代碼

<Grid>
    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <Label Content="Layer3 => "/>
            <Label Content="{Binding Layer3.Value}" Margin="20 0 0 0"/>
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <Label Content="Layer2 => "/>
            <Label Content="{Binding Layer2.Value}" Margin="20 0 0 0"/>
        </StackPanel>

        <StackPanel Orientation="Horizontal">
            <Label Content="Layer1 => "/>
            <Label Content="{Binding Layer1.Value}" Margin="20 0 0 0"/>
        </StackPanel>

        <Button Content="點擊" Click="ButtonBase_OnClick" HorizontalAlignment="Left"/>
    </StackPanel>
</Grid>

測試類代碼

public class Layer3 : NotifyPropertyChangedHelper
{
    public Layer2 SubLayer { get; set; } = new Layer2();
    public string Value
    {
        get => SubLayer.Value;
        set => SubLayer.Value = value;
    }
}

public class Layer2 : NotifyPropertyChangedHelper
{
    public Layer1 SubLayer { get; set; } = new Layer1();
    public string Value
    {
        get => SubLayer.Value;
        set => SubLayer.Value = value;
    }
}

public class Layer1 : NotifyPropertyChangedHelper
{
    public Layer1(string value = "NA")
    {
        Value = value;
    }
    public string Value { get; set; }
}

測試後臺代碼

public void Init()
{
    Layer1 = new Layer1("hello");

    Layer2 = new Layer2
    {
        SubLayer = Layer1
    };

    Layer3 = new Layer3
    {
        SubLayer = Layer2
    };
}

public void Test()
{
    var t = DateTime.Now.Millisecond.ToString();

    // ex1
    //Layer1.Value = t;

    // ex2.1
    //Layer2.SubLayer.Value = t;
	
	// ex2.2
	// Layer2.SubLayer = new Layer1(t);

	// ex2.3
	//Layer1.Value = t;
	//Layer2.SubLayer = Layer1;

    // ex3.1
    //Layer3.SubLayer.SubLayer = new Layer1(t);

    // ex3.2
    //Layer3.SubLayer = new Layer2() { SubLayer = new Layer1(t) };

	// ex4
	//Layer1.Value = t;
	//Layer3.OnPropertyChanged(nameof(Layer3.Value));
}

探索

初始界面
初始界面

測試用例ex1

Layer1.Value = t;

對於Layer1來說就是常見的普通屬性綁定,而Layer2Layer3這是嵌套屬性綁定。爲穩妥起見,Layer2Layer3均繼承了NotifyPropertyChangedHelper
public class Layer1,該情況很明顯,綁定失敗。
public class Layer1 : NotifyPropertyChangedHelper,只有Layer1刷新成功。
在這裏插入圖片描述

測試用例ex2

ex2.1

Layer2.SubLayer.Value = t;

仍然只有Layer1的數據刷新成功。
在這裏插入圖片描述

ex2.2

Layer2.SubLayer = new Layer1(t);

因爲沒有修改Layer1的內容,所以Layer1不刷新是正常的。
因爲重新給Layer2.SubLayer重新賦值,所以Layer2刷新成功。
在這裏插入圖片描述

ex2.3

Layer1.Value = t;
Layer2.SubLayer = Layer1;

爲了區分ex2.2,特別做了這個對比。如果賦值給Layer2.SubLayer的變量不是新的變量,那麼不會有刷新。
在這裏插入圖片描述

測試用例ex3

ex3.1

Layer3.SubLayer.SubLayer = new Layer1(t);

從代碼可知,只是對Layer2.SubLayer重新賦值,所以Layer2刷新成功。
在這裏插入圖片描述

ex3.2

Layer3.SubLayer = new Layer2() { SubLayer = new Layer1(t) };

這次對Layer3.SubLayer重新賦值,所以Layer3刷新成功。
在這裏插入圖片描述

測試用例ex4

Layer1.Value = t;
Layer3.OnPropertyChanged(nameof(Layer3.Value));

主動調用OnPropertyChanged,刷新指定屬性。
在這裏插入圖片描述

結論

由上面的例子可知

  1. 數據刷新是要通過OnPropertyChanged。當屬性被賦值時,調用OnPropertyChanged進行刷新。
  2. 但是嵌套屬性中,下層屬性賦值無法觸發上層屬性調用OnPropertyChanged,所以出現下層數據更新,但是上層沒有刷新的情況。除非主動刷新,如ex4。但這樣代碼就顯得很冗餘。
  3. 目前我暫時沒有好的方法能實現逐層嵌套的屬性數據刷新,勉強用重新賦值的方式,刷新最上層。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章