如何禁止验证错误的自动数据绑定

时间:2012-05-14 20:48:50

标签: c# wpf data-binding mvvm

我正在使用MVVM作为中继命令和数据绑定在C#WPF中创建一个简单的数据库应用程序。对于数据库内容的内存存储,我使用ObservableCollection,它绑定到Datagrid,如下所示:

<DataGrid ItemsSource="{Binding Path=Softwares, Mode=OneWay}" SelectedItem="{Binding Path=SoftwareSelection, Mode=TwoWay}">

当选择项目时,用户可以选择编辑它。对于编辑,打开一个表单,其中包含一组带有给定实体数据的文本框。所有字段都使用IDataErrorInfo进行验证,除非所有文本框都有效,否则不会启用ok按钮,因此不能将更改保存到集合和数据库中。

以下是示例文本框的外观:

<TextBox Text="{Binding Name, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnExceptions=True}"/>

但棘手的部分是,如果我在文本框中更改某些值然后关闭窗口,新值将传播到ObservableCollection,这是我不想要的。你有什么想法,如何防止这种行为?我想在点击按钮后才能进行数据绑定工作。否则,数据绑定工作正常,因此按钮(dis / en)在单击后显示对数据库和集合的更改。两个视图都由不同的ViewModel提供服务,视图之间的数据通过触发事件传递。

我尝试将DataGrid UpdateSourceTrigger=Explicit添加到ItemsSource绑定中,但没有帮助。也许,我错过了一些应用程序逻辑?

非常感谢你的帮助。

3 个答案:

答案 0 :(得分:1)

这是大多数WPF开发人员犯错误的地方!

在MVVM中,脏数据可以存储在ViewModel中,这就是VM层的用途!它模仿View的{​​{1}}视角,因为Model出错,View也会出错。这完全有效。

所以说过,问题仍然存在

  

您如何不允许临时 / 数据流入您的   的ObservableCollection?

两种方式......

  1. 如果您的ViewModel特定于您的模型类(例如ObservableCollection),那么如果您的Model类(MyItem)是一个实体类\ DAL类\ NHibernate类创建名为MyItem的{​​{1}}类的包装,然后使用MyItem代替ViewModelMyItem

    这样来自ObservableCollection<MyItem>的脏数据就会在ObservableCollection<ViewModelMyItem>内,并且只有合法地返回到您的模型类(View)才会ViewModelMyItem按钮点击。这意味着在MyItem的{​​{1}}委托中,您可以将Save的属性复制\克隆到Save Command的属性中,如果Execute()中的验证是精细。

    因此,如果ViewModelMyItemItem类/ ViewModelMyItem类/ Item客户端模型类,则始终只有EntityType过滤的有效数据临时/脏信息。

  2. 您可以使用NHibernate绑定模型。它会阻止WCF数据返回到ViewModelMyItem,除非明确调用Explicit

    但是根据我的说法,这会以直截了当的方式击败MVVM,因为TwoWay不会有UI显示的内容!但是,您仍然可以使用* 附加行为* 通过保留在MVVM空间来管理显式绑定!

  3. 请告诉我这是否有帮助!

答案 1 :(得分:0)

最好将代码放入域对象的属性设置器中。然后通过触发NotifyPropertyChanged处理程序与视觉效果同步。

有关此主题的更多信息:
http://msdn.microsoft.com/en-us/library/ms743695.aspx
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

答案 2 :(得分:0)

将绑定模式设置为显式应该要求您调用绑定表达式UpdateSource()方法将更改发送回模型。因为您只提到在DataGrid的绑定上设置了Explicit,所以我猜你只需要确保在任何直接绑定到模型的属性上显式设置该模式。例如你的TextBox的Text Binding,在上面的例子中。这可能会解决您的问题,但需要您以某种方式在每个目标的BindingExpression上调用UpdateSource()。

如果您正在使用主流ORM之一(EF,Linq to SQL等),那么您的实体可能会自动实现INotifyPropertyChanged和INotifyPropertyChanging。由于您正在共享对单个实例的引用,因此编辑中的所有更改都将反映在主视图中以及绑定到该实例的任何其他内容中。作为一个更脏的替代方法,您可以创建一个相同类型的单独实例,并在窗口的对话框结果为true时手动复制值。

第一种方法要求您手动更新绑定,第二种方法要求您手动更新Edit实例中的值。

通过更多代码,我可以帮助您了解具体方法。