我试图让我的问题变得简单明了。
目前,如果我有一个更新基础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。 Bound
到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
这就是我必须这样做的原因。对于上面的文本框,这是我想要允许发生的事情:
它应显示Meeting.TFGW.BibleReadingItem.Main.Name
的内容(会议已经是绑定属性)。
当您从日期组合中选择其他会议时,此文本框应该更新。
如果用户从DataGrid
和中选择了一个名称,则ActiveAstudentAssignmentType
组合设置为StudentAssignmentType::BibleReadingMain
,那么我还想更新文本框。
我认为我感到困惑的是当我应该从INotifyPropertyChanged
派生我的课程。我的模型数据是具有自己数据的会议对象。所有这些都应该从INotifyPropertyChanged继承并提升OnPropertyChanged吗?目前我没有在任何地方实施。我说谎,我实现它的唯一地方是视图模型本身:
public class OCLMEditorViewModel : INotifyPropertyChanged
所以这就是我必须按照我的方式去做的原因。
更清楚吗?
答案 0 :(得分:0)
基于所有评论并进一步研究......
其中一位answers声明:
- 创建了Viewmodel并包装了模型
- Viewmodel 订阅模型的PropertyChanged事件
- 将Viewmodel设置为视图的DataContext,绑定属性等
- 查看触发器对viewmodel的操作
- Viewmodel在模型上调用方法
- 模型自行更新
- Viewmodel处理模型的PropertyChanged并在响应中引发自己的PropertyChanged
- 视图反映了其绑定的变化,关闭了反馈循环
醇>
我还读了一些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 通知查看。