如果您真正使用 MVVM,那么您的 OK 按钮单击必须由某些Command
. 此命令必须来自您的ViewModel
. 绑定的Expliticly
属性必须来自您的ViewModel
再次。那是什么阻止了你。
- 不要使用
Explicit
绑定,而是使用OneWay
绑定。
- 在您的按钮中,绑定命令并将命令参数绑定到
OneWay
绑定的 Dependency 属性。
- 在 Command 的 Execute 处理程序(必须是 ViewModel 中的某个方法)中,使用传入的参数更改 ViewModel 的属性。
- 从
NotifyPropertyChanged
您的ViewModel
.
例如
假设我需要在单击 OK 按钮时将 TextBox 的 Text 更新回我的模型中。
因此,为此我有一个EmployeeViewModel
具有EmployeeName
属性的类。该属性有一个 getter 和一个 setter。设置器引发属性更改通知。视图模型还有另一个ICommand
名为的类型的属性,SaveNameCommand
它返回一个命令供我执行。
EmployeeViewModel
是我的视图的数据上下文类型。Myview 有一个TextBox
(命名为 x:Name="EmployeeNameTxBx")OneWay
绑定到EmployeeName
和一个 Button 作为OK
。我将Button.Command
属性绑定到EmployeeViewModel.SaveNameCommand
属性并Button.CommandParameter
绑定到EmployeeNameTxBx.Text
属性。
<StackPanel>
<TextBox x:Name="EmployeeNameTxBx"
Text="{Binding EmployeeName, Mode=OneWay}" />
<Button Content="OK"
Command="{Binding SaveNameCommand}"
CommandParameter="{Bidning Text, ElementName=EmployeeNameTxBx}" />
</StackPanel>
在我里面我EmployeeViewModel
有OnSaveNameCommandExecute(object param)
方法来执行我的SaveNameCommand
.
在此执行此代码...
var text = (string)param;
this.EmployeeName = text;
这种方式只有 OK 按钮单击,将 TextBox 的文本更新回EmployeeName
模型的属性。
编辑
查看您在下面的评论,我看到您正在尝试在 UI 上实现验证。现在这改变了一些事情。
IDataErrorInfo
只有当您的输入控件(例如 TextBoxes)是双向绑定时,相关验证才有效。是的,这就是它的意图。所以现在你可能会问“如果我们使用 IDataErrorInfo,这是否意味着不允许无效数据传递给模型的整个概念在 MVVM 中是徒劳的”?
实际上不是!
请参阅 MVVM 不强制执行仅应返回有效数据的规则。它接受无效数据,这就是IDataErrorInfo
工作原理并引发错误通知。关键是 ViewModel 只是您的 View 的软拷贝,因此它可能很脏。它应该确保的是,这种脏污不会被提交给您的外部接口,例如服务或数据库。
这种无效数据流应该ViewModel
通过测试无效数据来限制。如果我们TwoWay
启用了绑定,这些数据就会出现。因此,考虑到您正在实施,IDataErrorInfo
那么您需要拥有TwoWay
在 MVVM 中完全允许的绑定。
方法一:
如果我想在按钮单击时明确验证 UI 上的某些项目怎么办?
为此,请使用延迟验证技巧。在您的 ViewModel 中有一个名为 isValidating 的标志。默认设置为假。
在您的IDataErrorInfo.this
属性中,通过检查 isValidating 标志跳过验证...
string IDataErrorInfo.this[string columnName]
{
get
{
if (!isValidating) return string.Empty;
string result = string.Empty;
bool value = false;
if (columnName == "EmployeeName")
{
if (string.IsNullOrEmpty(AccountType))
{
result = "EmployeeName cannot be empty!";
value = true;
}
}
return result;
}
}
然后在您的 OK 命令执行的处理程序中,检查员工姓名,然后为同一属性引发属性更改通知事件......
private void OnSaveNameCommandExecute(object param)
{
isValidating = true;
this.NotifyPropertyChanged("EmployeeName");
isValidating = false;
}
仅当您单击确定时才会触发验证。请记住,EmployeeName
必须包含无效数据才能进行验证。
方法二:
如果我想在 MVVM 中显式更新没有 TwoWay 模式的绑定怎么办?
然后你将不得不使用Attached Behavior
. 该行为将附加到 OK 按钮,并将接受需要刷新其绑定的所有项目的列表。
<Button Content="OK">
<local:SpecialBindingBehavior.DependentControls>
<MultiBinding Converter="{StaticResource ListMaker}">
<Binding ElementName="EmployeeNameTxBx" />
<Binding ElementName="EmployeeSalaryTxBx" />
....
<MultiBinding>
</local:SpecialBindingBehavior.DependentControls>
</Button>
这ListMaker
是一个IMultiValueConverter
简单地将值转换为列表的...
Convert(object[] values, ...)
{
return values.ToList();
}
在您SpecialBindingBehavior
的DependentControls
属性更改处理程序中...
private static void OnDependentControlsChanged(
DependencyObject depObj,
DependencyPropertyChangedEventArgs e)
{
var button = sender as Button;
if (button != null && e.NewValue is IList)
{
button.Click
+= new RoutedEventHandler(
(object s, RoutedEventArgs args) =>
{
foreach(var element in (IList)e.NewValue)
{
var bndExp
= ((TextBox)element).GetBindingExpression(
((TextBox)element).Textproperty);
bndExp.UpdateSource();
}
});
}
}
但我仍然建议您使用我之前基于纯 MVVM 的 **Approach 1。