触发INotifyPropertyChanged.PropertyChanged依赖/嵌套视图模型上的属性



我有一个嵌套的视图模型结构,如下面的例子所示:

public class SubViewModel : INotifyPropertyChanged
{
    public string Property
    {
        get
        {
            // calculate result and return it
        }
    }
}
public class ViewModel : INotifyPropertyChanged
{
    public SubViewModel Sub { get; set; }
    public void MyMethod()
    {
        // executes code that changes some parameters such that Sub.Property changes
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Sub.Property"));
    }
}

在某些情况下,父视图模型中的更改会影响嵌套视图模型的属性。换句话说,子视图模型上的一个属性(在这个例子中是SubViewModel.Property)发生了变化,但是子视图模型并不知道。

我想以一种方式调用PropertyChanged,告诉WPF绑定引擎子视图模型Sub上的属性Property已经更改。我尝试了以下所有选项,但到目前为止都不起作用:

OnPropertyChanged("");
OnPropertyChanged("*");
OnPropertyChanged("Sub");
OnPropertyChanged("Sub.Property");
OnPropertyChanged("Sub.*");

有办法做到这一点吗?

请注意:我知道父视图模型可以调用子视图模型上的方法,这会引发子视图模型上的PropertyChanged事件。我有我的理由不那样做。

  • 当你改变SubViewModel时调用OnPropertyChanged。
  • 你的SubviewModel应该创建在你的MainViewModel
  • 在你的视图中你必须调用:"DataContext ={Binding Sub}"
  • 在你的子视图中不能有"DataContext"这个词
  • 在你的SubView中,你必须像这样绑定属性:"Example = {Binding MyProperty}"

    public class SubViewModel : INotifyPropertyChanged
    {
       private string _MyProperty;
       public string MyProperty
       {
           get { return _MyProperty; }
           set { _MyProperty = value;
               NotifyPropertyChanged();
           }
       }
       #region NotifyPropertyChanged
       public event PropertyChangedEventHandler PropertyChanged;
       private void NotifyPropertyChanged([CallerMemberName] string info = null)
       {
           PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
       }
       #endregion
    }
    public class ViewModel : INotifyPropertyChanged
    {
       private SubViewModel _Sub;
       public SubViewModel Sub
       {
           get { return _Sub; }
           set { _Sub = value;
            NotifyPropertyChanged();
           }
       }
       public void MyMethod()
       {
        // executes code that changes some parameters such that Sub.Property changes
           NotifyPropertyChanged();
       }
       #region NotifyPropertyChanged
       public event PropertyChangedEventHandler PropertyChanged;
       private void NotifyPropertyChanged([CallerMemberName] string info = null)
       {
           PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
       }
       #endregion
    }
    

SubViewModel中创建一个事件,并在发生变化时引发该事件。父视图模型将订阅该事件。

您正在创建ViewModelSubViewModel之间的循环依赖关系。这导致两者之间的强耦合,这从来都不是好事。我提出了一个不同的解决方案。INotifyPropertyChanged已经提供了基础设施来完成您想要的。

所以SubViewModel依赖于ViewModel。我假设它需要ViewModel的一个属性的值来计算SubViewModel.Property的值。因此,解决方案很自然地将SubViewModel连接到ViewModel.PropertyChanged:

public class SubViewModel : INotifyPropertyChanged
{
    private ViewModel parent;
    public event PropertyChangedEventHandler PropertyChanged;
    public SubViewModel(ViewModel parent)
    {
        this.parent = parent;
        // Hook up to parent's property changes.
        this.parent.PropertyChanged += (sender, e) => 
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SubProperty"));
    }
    public string SubProperty
    {
        get { return parent.Property; }
    }
}

请注意,通过在SubViewModel的构造函数中期望ViewModel来显式地实现依赖关系。这样,下一个程序员立即看到SubViewModel需要ViewModel才能正常工作,而不能构造一个不能正常工作的SubViewModel

在构造函数中定义的事件处理程序当然是相当简化的。最好让它成为一个私有方法,在e.PropertyName做任何事情之前检查它。无论如何,它的基本目的是通知所有订阅SubViewModel属性更改的客户端,只要ViewModel.Property已经更改。

为了避免循环依赖,最好不要有从ViewModelSubViewModel的关系。去掉Sub属性,像这样实现ViewModel:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private string property;
    public string Property
    {
        get { return this.property; }
        set
        {
            this.property = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Property"));
        }
    }
}

注意ViewModel的实现看起来与任何其他INotifyPropertyChanged实现完全相同。父进程不需要知道它的子进程如何处理它的值。只有ViewModel的客户端实现了处理ViewModel的属性更改的逻辑,而不是父级。

下面是一个测试的工作示例:https://dotnetfiddle.net/vQJBak

相关内容

  • 没有找到相关文章

最新更新