【发布时间】:2016-11-29 18:04:49
【问题描述】:
我有一个基于DataGrid 的Appointment 对象视图。当用户双击一行时,我打开一个模型窗口来查看/编辑单击的约会。我通过下面的命令执行此操作,绑定到LeftDoubleClick 鼠标事件。绑定有效,命令被正确调用。
_doubleClickCommand = new DelegateCommand<AppointmentRowViewModel>(async p =>
{
if (BossViewModel.ShowModalCommand.CanExecute(null))
{
var modal = new AppointmentFormWindow();
await modal.ViewModel.Populate(p.Id, Cts.Token);
BossViewModel.ShowModalCommand.Execute(modal);
}
},
p => true
);
选定的项目和命令参数p 是AppointmentRowViewModel,是AppointmentDto 对象的纯粹表示模型,仅具有属性和零逻辑。
BossViewModel 是MainWindow 的视图模型,负责管理显示哪个视图,在这种情况下,用于显示模态框和消息框。我把这个责任放在这里是因为消息框需要一个所有者窗口,这是唯一知道其视图的视图模型。从MainWindowViewModel 打开和管理其他窗口也很有意义。
所以DoubleClickCommand 创建了一个它想要打开的窗口的实例,并且该窗口的 XAML 在这种情况下为它分配了一个AppointmentFormViewModel。该命令在该视图模型上调用 Populate 以加载约会并将其映射到该视图模型:
public override async Task Populate(int? entityId = null, CancellationToken cancellation = new CancellationToken())
{
if (entityId.HasValue)
{
await _apptService.Load(entityId.Value, this, cancellation);
}
IsInitialized = true;
OnAllPropertiesChanged();
}
我像这样使用INotifyPropertyChanged:
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnAllPropertiesChanged()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(string.Empty));
}
然后BossViewModel.ShowModalCommand 看起来像这样:
_showModalCommand = new DelegateCommand<IModal>(async modal =>
{
modal.ViewModel.BossViewModel = this;
modal.ShowDialog();
},
a => !ModalOpen
);
一切正常,约会从数据库加载,映射到它的视图模型,它已经分配给AppointmentGridWindow。模式打开,但其视图模型已完全填充,没有更新表单字段以反映视图模型属性值。就好像我正在创建一个新约会。
我所有的数据绑定都使用“Mode=TwoWay, NotifyOnSourceUpdated=True”,所以我希望在视图模型上设置一个值并提高PropertyChanged 会更新视图元素,但视图仍然存在完全空白。
更新:这是来自视图的 XAML 摘录,而不是空白。它们绑定的视图模型属性都具有有效值,因为该表单仅适用于捕获。
<Window.DataContext>
<vm:AppointmentFormViewModel />
</Window.DataContext>
.....
<TextBlock Text="Topic:" />
<TextBox Text="{Binding Topic, Mode=TwoWay}" />
<TextBlock Text="Venue: " />
<TextBox Text="{Binding Venue, Mode=TwoWay}" />
<TextBlock Text="Start Date: " />
<DatePicker SelectedDate="{Binding StartDate, Mode=TwoWay}" />
<ComboBox IsEditable="False" ItemsSource="{Binding TimeList}" SelectedItem="{Binding Path=StartTime, Mode=TwoWay}" />
<TextBlock Text="End Date: "/>
<DatePicker SelectedDate="{Binding EndDate}" />
<ComboBox IsEditable="False" ItemsSource="{Binding Path=TimeList}" SelectedItem="{Binding Path=EndTime, Mode=TwoWay}" />
....
<DataGrid x:Name="TheList" Grid.Row="1" ItemsSource="{Binding Attendees}"....>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding GivenName}" Header="Given Name" />
<DataGridTextColumn Binding="{Binding FamilyName}" Header="Family Name" />
<DataGridTextColumn Binding="{Binding Phone}" Header="Phone" />
<DataGridTextColumn Binding="{Binding EMail}" Header="Email" />
<DataGridTextColumn Binding="{Binding Position}" Header="Position" />
<DataGridTextColumn Binding="{Binding OrgName}" Header="Org." />
<DataGridTextColumn Binding="{Binding BranchName}" Header="Branch" />
</DataGrid.Columns>
问题已解决:突然间,经过大量代码检查、对上述代码摘录的编辑以及一些 Git 回滚,现在可以正确填充相关视图。我认为它正在绑定TwoWay,但是当我第一次这样做时,它不起作用。还有一些问题是,在为回答下面的 cmets 做所有的摆弄时,我以某种方式将某些东西恢复到了正确的状态。
感谢所有评论者的建议和帮助。
【问题讨论】:
-
发布(部分)XAML,并在“输出”窗口中查找绑定错误。
-
确保从 UI 线程调用 UI 通知方法。这里有很多异步操作,如果不在 UI 线程上执行 UI 更改可能会丢失。
-
另外,VS 中的应用程序输出窗口可能会显示一些未引发异常的绑定错误。这可能是有用的信息。
-
“我所有的数据绑定都使用 Mode=TwoWay,NotifyOnSourceUpdated=True”——你根本不知道这些标志的实际含义是什么,是吗?
-
Mode=TwoWay表示当目标值更改时,target(UI 控件属性)值被复制回源(视图模型)。当值从绑定目标传输到绑定源时,NotifyOnSourceUpdated会引发Binding.SourceUpdated事件。您是否正在处理所有绑定上的SourceUpdated事件?这就是它的名字,SourceUpdated。你是否明确地给他们一个事件处理程序?
标签: c# wpf mvvm data-binding inotifypropertychanged