在同一个Setter中调用多个OnPropertyChanged(或者还有另一种简单方法)

时间:2016-07-03 13:08:40

标签: c# mvvm

我试图让我的问题变得简单明了。

目前,如果我有一个更新基础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其中某些来源已更改?

我已阅读有关在OnPropertyChanged类中实现相同Model功能的内容。因此,XAML将接收它。但我认为MWWV的那两部分我们不应该彼此了解。

问题是,其他3个处于禁用控件中,但它们可以从窗口上的两个位置更新。所以我认为我不能有两个更新源触发器吗?

谢谢。

第二次尝试解释事物:

Meeting个对象的ObservableCollection。 BoundComboBox

<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,那么我还想更新文本框。

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

    public class OCLMEditorViewModel : INotifyPropertyChanged
    

    所以这就是我必须按照我的方式去做的原因。

    更清楚吗?

1 个答案:

答案 0 :(得分:0)

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

其中一位answers声明:

  
      
  1. 创建了Viewmodel并包装了模型
  2.   
  3. Viewmodel 订阅模型的PropertyChanged事件
  4.   
  5. 将Viewmodel设置为视图的DataContext,绑定属性等
  6.   
  7. 查看触发器对viewmodel的操作
  8.   
  9. Viewmodel在模型上调用方法
  10.   
  11. 模型自行更新
  12.   
  13. Viewmodel处理模型的PropertyChanged并在响应中引发自己的PropertyChanged
  14.   
  15. 视图反映了其绑定的变化,关闭了反馈循环
  16.   

我还读了一些this(这让我有点困惑),其中说:

  

如果基础数据存储中的数据发生了变化,模型会通知 ViewModel。

所以,我做的第一件事就是将我的Meeting对象改为派生自INotifyPropertyChanged。此外,我添加了新属性以获取对会议模型中更深层数据的访问权限。示例(剥离):

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值,我们可以直接更新来源属性。因此TextBox会因PropertyChange监听器而自动了解它。

因此,原始会议属性代码现在如下所示:

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 通知查看