用于对嵌套属性进行更改通知的模式

本文关键字:通知 模式 嵌套 属性 用于 | 更新日期: 2023-09-27 18:15:12

我想绑定到我的ViewModel的属性的属性。嵌套对象在编译时是未知的,所以我不能直接将绑定路径设置为它的一个属性。相反,我将对象作为一个整体绑定,然后值转换器使用反射找出感兴趣的属性(或多个属性)。

绑定和值转换器最初工作良好,但如果嵌套属性的值被更改,则不会调用值转换器(如果在VM中更改了对该对象的引用)。VM和嵌套类都实现了INotifyPropertyChanged

这里是一个简化的例子,如果Name的值最初设置为"Bond",则秘密被揭示,但如果组合框的值在程序运行时更改为"Bond",则永远不会泄露:

XAML:

<Window.Resources>
    <local:ViewModel x:Key="vm" />
    <local:NameToVisConverter x:Key="NameToVis" />
</Window.Resources>
<StackPanel DataContext="{StaticResource vm}">
    <ComboBox SelectedValue="{Binding MyPoco.Name}">
        <sys:String>Smith</sys:String>
        <sys:String>Jones</sys:String>
        <sys:String>Bond</sys:String>
    </ComboBox>
    <Label Visibility="{Binding MyPoco, Converter={StaticResource NameToVis}}">
        Secret!
    </Label>
</StackPanel>

视图模型,嵌套类:

public class ViewModel : BindableBase
{
    public Poco MyPoco
    {
        get { return _MyPoco; }
        set { SetProperty(ref _MyPoco, value); }
    }
    private Poco _MyPoco = new Poco();
}
public class Poco : BindableBase
{
    public String Name
    {
        get { return _Name; }
        set { SetProperty(ref _Name, value); }
    }
    private String _Name;
}

注: BindableBase及其SetProperty()由Prism提供,实现INotifyPropertyChanged

来自NameToVisConverter的值转换方法:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
    return (value as Poco).Name == "Bond"
        ? Visibility.Visible
        : Visibility.Collapsed;
}

我天真地认为,如果绑定是在对象本身而不是对象的一个属性上更改了INotifyPropertyChanged类的属性,那么绑定将会收到警报。显然不是……是否有一个好的模式(或者,希望是一个简单的解决方案)来处理这种情况?

用于对嵌套属性进行更改通知的模式

如果我是你,当MyPoco的任何属性发生变化(或应该被假定已经改变,或无论情况如何)时,我只会让父VM提高PropertyChanged("MyPoco")。这将导致绑定更新目标,并且将调用转换器的Convert

替代方案将涉及您必须编写、调试和维护的c#代码,这是在XAML绑定到不可变的属性值对象的属性或不实现INotifyPropertyChanged的情况下使用INotifyPropertyChanged的完美正常方式。例如,我绑定了StringProperty.Length几次,或者NullableProperty.HasValue