[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. 目前我暂时没有好的方法能实现逐层嵌套的属性数据刷新,勉强用重新赋值的方式,刷新最上层。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章