【问题标题】:Trigger INotifyPropertyChanged.PropertyChanged for property on dependent / nested view model为依赖/嵌套视图模型上的属性触发 INotifyPropertyChanged.PropertyChanged
【发布时间】:2016-06-27 21:14:24
【问题描述】:

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

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 事件。我有理由不那样做。

【问题讨论】:

  • 也许你应该解释你这样做的原因。那么我们或许可以帮助您找出更好的方法来实现您的目标。
  • 说真的我还是不太明白你的意思,不过你可以打OnPropertyChangedinternal,然后打电话Sub.OnPropertyChanged("Property")。我只是在猜测你想要什么,但谁知道 - 这可能是你需要的东西。
  • 为什么不能简单地从子视图模型中的每个属性中引发 PropertyChanged 事件。这样当您在主视图模型中更改 subviewmodelinstance.PropertyName 时,将自动引发相应的事件。这是正常的方式。我认为您不需要通过调用子视图模型中的函数来引发事件。
  • SubProperty 的 getter 内部发生了什么?它是否读取ViewModel 的属性?请解释一下依赖项到底是什么。

标签: wpf binding inotifypropertychanged


【解决方案1】:
  • 更改 SubViewModel 时调用 OnPropertyChanged。
  • 您的 SubviewModel 应该在您的 MainViewModel 中创建
  • 在您的视图中,您必须调用:“DataContext ={Binding Sub}”
  • 在您的 SubView 中不得包含“DataContext”一词
  • 在您的 SubView 中,您必须像这样绑定属性: "示例 = {绑定 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
    }
    

【讨论】:

    【解决方案2】:

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

    这就是事件的用途。

    【讨论】:

    • 不应该反过来吗(即SubViewModel订阅ViewModel.PropertyChanged)?
    • @Abbondanza 你明白了。
    【解决方案3】:

    您正在创建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。无论如何,它的基本目的是在ViewModel.Property 发生更改时通知所有订阅SubViewModel 属性更改的客户端。

    为了避免循环依赖,最好不要从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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-19
      • 2014-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多