在同一个Setter中调用多个OnPropertyChanged(或者有其他简单的方法)

本文关键字:其他 或者 简单 方法 OnPropertyChanged Setter 同一个 调用 | 更新日期: 2023-09-27 17:54:08

我尽量使我的问题简单扼要。

目前,如果我有一个更新底层Model数据的属性,因此它需要通知其他一些属性源已经更改,我这样做:

public Data.MeetingInfo.Meeting Meeting
{
    get { return _Meeting; }
    set
    {
        if(value != null)
        {
            _Meeting = value;
            if (_Meeting.IsDirty)
            {
                _Model.Serialize();
                _Meeting.MarkClean();
                OnPropertyChanged("Meeting");
                OnPropertyChanged("BibleReadingMain");
                OnPropertyChanged("BibleReadingClass1");
                OnPropertyChanged("BibleReadingClass2");
            }
        }
    }
}
private Data.MeetingInfo.Meeting _Meeting;

可以看到,我添加了几个不同的OnPropertyChanged方法调用。这样做可以接受吗?或者,Model的特定性质会告诉View它的某些来源发生了变化吗?

我读过关于在Model类中实现相同的OnPropertyChanged功能的文章。因此,XAML将拾取它。但是我认为MWWV的这两个部分我们不应该知道彼此。

问题是,其他3是在禁用控件,但他们可以从窗口上的两个地方更新。所以我认为我不能有两个更新源触发器,对吧?

谢谢。

第二次解释:

ObservableCollection of Meeting对象。Bound to a ComboBox:

<ComboBox x:Name="comboMeetingWeek" ItemsSource="{Binding Meetings}"
                                    SelectedItem="{Binding Meeting, UpdateSourceTrigger=PropertyChanged}" />

Meeting对象包含几个属性。我们用这些属性绑定窗口上的控件。例子:

<ComboBox x:Name="comboNotes" IsEditable="True"
          DataContext="{Binding Meeting}"
          Text="{Binding Note, UpdateSourceTrigger=LostFocus}"
          ItemsSource="{StaticResource Notes}"/>

我对大多数控件都这样做。因此,视图模型中的Meeting属性保持最新,然后当您选择不同的会议时,它将其提交到模型数据并显示新会议(如前所述)。

但是,在窗口的某些地方,我有一些禁用的文本框。这些属性与嵌套在Meeting对象中的属性相关联。例如:

 <TextBox x:Name="textBibleReadingMain" Grid.Column="0" Margin="2" IsEnabled="False"
          DataContext="{Binding TFGW.BibleReadingItem.Main}"
          Text="{Binding DataContext.BibleReadingMain, ElementName=oclmEditor, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"/>

TabItem已经将其DataContext设置为{Binding Meeting}。我们需要在文本框中显示的内容是:

Meeting (current context).TFGW.BibleReadingItem.Main.Name

这就是为什么我必须做我做过的事。对于上面的文本框,这是我想允许发生的:

  1. 它应该显示Meeting.TFGW.BibleReadingItem.Main.Name的内容(会议已经是一个绑定属性)

  2. 当您从日期组合中选择不同的会议时,此文本框应更新。

  3. 如果用户从DataGrid 中选择一个名称,ActiveAstudentAssignmentType组合被设置为StudentAssignmentType::BibleReadingMain,那么我也想更新文本框。

我想我感到困惑的是我应该从INotifyPropertyChanged派生我的类。我的模型数据是会议对象和它自己的数据。所有这些都应该从INotifyPropertyChanged继承和提高OnPropertyChanged?目前,我没有在任何地方实施。我说谎,我实现它的唯一地方是视图模型本身:

public class OCLMEditorViewModel : INotifyPropertyChanged

所以这就是为什么我必须这样做。

清晰吗?

在同一个Setter中调用多个OnPropertyChanged(或者有其他简单的方法)

基于所有的评论和进一步的研究....

其中一个答案是:

  1. 视图模型被创建并包装模型
  2. Viewmodel 订阅模型的PropertyChanged事件
  3. Viewmodel被设置为view的DataContext,属性被绑定等等
  4. 视图触发视图模型
  5. 操作
  6. 视图模型调用模型上的方法
  7. 模型自我更新
  8. Viewmodel处理模型的PropertyChanged并在响应
  9. 中引发自己的PropertyChanged
  10. 视图反映其绑定的变化,关闭反馈循环

我也读了一点(这让我有些困惑),它说:

如果底层数据存储中的数据发生了变化,Model 会通知 ViewModel。

所以,我做的第一件事是改变我的Meeting对象从INotifyPropertyChanged派生。此外,我还添加了新的属性,用于访问Meeting模型中的更深层数据。示例(精简):

public class Meeting : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    #region Bible Reading Name Properties
    [XmlIgnore]
    public string BibleReadingMainName
    {
        get { return _TFGW.BibleReadingItem.Main.Name; }
        set
        {
            _TFGW.BibleReadingItem.Main.Name = value;
            OnPropertyChanged("BibleReadingMainName");
        }
    }
    [XmlIgnore]
    public string BibleReadingClass1Name
    {
        get { return _TFGW.BibleReadingItem.Class1.Name; }
        set
        {
            _TFGW.BibleReadingItem.Class1.Name = value;
            OnPropertyChanged("BibleReadingClass1Name");
        }
    }
    [XmlIgnore]
    public string BibleReadingClass2Name
    {
        get { return _TFGW.BibleReadingItem.Class2.Name; }
        set
        {
            _TFGW.BibleReadingItem.Class2.Name = value;
            OnPropertyChanged("BibleReadingClass2Name");
        }
    }
    #endregion
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

在我的ViewModel我将其设置为PropertyChanged的侦听器:

_Meeting.PropertyChanged += Meeting_PropertyChanged;

在这个时间点,处理程序只是传递被更改的属性:

private void Meeting_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    OnPropertyChanged(e.PropertyName);
}

在我的XAML中,我调整了TextBox以使用新属性,并删除了DataContext引用。现在我有:

<TextBox x:Name="textBibleReadingMain" Grid.Column="0" Margin="2" IsEnabled="False"
        Text="{Binding BibleReadingMainName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>

在右边,我有DataGrid,当我们点击一行,SelectedStudentItem被更新,我们现在可以做:

private Student _SelectedStudentItem;
public Student SelectedStudentItem
{
    get
    {
        return _SelectedStudentItem;
    }
    set
    {
        // We need to remove this item from the previous student history
        if (_SelectedStudentItem != null)
            _SelectedStudentItem.History.Remove(Meeting.DateMeeting);
        _SelectedStudentItem = value;
        if (_SelectedStudentItem == null)
            return;
        _EditStudentButtonClickCommand.RaiseCanExecuteChanged();
        _DeleteStudentButtonClickCommand.RaiseCanExecuteChanged();
        OnPropertyChanged("SelectedStudentItem");
        if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingMain)
            _Meeting.BibleReadingMainName = _SelectedStudentItem.Name;
        else if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingClass1)
            _Meeting.BibleReadingClass1Name = _SelectedStudentItem.Name;
        else if (ActiveStudentAssignmentType == StudentAssignmentType.BibleReadingClass2)
            _Meeting.BibleReadingClass2Name = _SelectedStudentItem.Name;
    }

基于当前ActiveStudentAssignmentType的值,我们可以直接更新source属性。因此,TextBox将自动知道它,因为PropertyChange侦听器。

因此,原来的Meeting属性代码现在看起来像这样:
public Data.MeetingInfo.Meeting Meeting
{
    get { return _Meeting; }
    set
    {
        // Has the existing meeting object changed at all?
        if(_Meeting != null && _Meeting.IsDirty)
        {
            // Yes, so save it
            _Model.Serialize();
            _Meeting.MarkClean();
        }
        // Now we can update to new value
        if (value != null)
        {
            _Meeting = value;
            OnPropertyChanged("Meeting");
        }
    }
}
private Data.MeetingInfo.Meeting _Meeting;

所有那些额外的OnPropertyChanged调用现在已经过时了!

我缺少的是实现通知模型ViewModel。然后是ViewModel通知View

相关文章: