在这个例子中,UpdateSourceTrigger设置为Explicit,然后在视图代码中调用TextBox名称的UpdateSource。
但是如果我使用MVVM dp,我不想给我的控件命名,源属性在VM中而不是在视图中,那么将控件绑定到VM属性并将UpdateSourceTrigger设置为explicit的正确方法是什么?
我想这样做是因为在我的情况下,它是ShowDialog窗口,我希望只有当用户点击“确定”时才更新源。
预先感谢!
EmployeeViewModel
类,其中包含 EmployeeName
属性。该属性具有 getter 和 setter。setter 引发属性更改通知。视图模型还具有另一个类型为 ICommand
的属性,命名为 SaveNameCommand
,它返回一个要执行的命令。
EmployeeViewModel
是我的视图的数据上下文类型。我的视图有一个名为 x:Name="EmployeeNameTxBx" 的 TextBox
,单向绑定到 EmployeeName
,并具有一个名为“ 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;
仅通过单击“确定”按钮,将文本框中的文本更新回模型的EmployeeName
属性。
编辑
根据您在下面的评论中所述,我发现您正在尝试在UI上实现验证。这样有点改变了事情。
IDataErrorInfo
和相关的验证仅在您的输入控件(如文本框)是双向绑定时才有效。是的,这就是它的意图。那么现在你可能会问“如果我们使用IDataErrorInfo,这是否意味着不允许无效数据传递到模型的整个概念在MVVM中是徒劳的?”
实际上并非如此!
请注意,MVVM不强制规定仅应返回有效数据。它接受无效数据,这就是IDataErrorInfo
工作并引发错误通知的方式。关键点是ViewModel只是您的View的纯粹副本,因此它可以是脏的。它应该确保这种肮脏不被提交到外部接口,如服务或数据库。
这种无效数据流应由ViewModel
通过测试无效数据来限制。如果启用了TwoWay
绑定,则该数据将传递。因此,如果您正在实现IDataErrorInfo
,则需要使用TwoWay
绑定,这在MVVM中是完全允许的。
方法1:
如果我想在单击按钮时显式验证某些UI上的项目怎么办?
为此,请使用延迟验证技巧。在ViewModel中有一个名为isValidating的标志。默认情况下将其设置为false。
在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
必须包含无效数据,以便验证能够生效。
方法2:
如果我想在MVVM中不使用TwoWay模式来显式更新绑定怎么办?
那么您就必须使用附加行为
。该行为将附加到“确定”按钮,并将接受需要刷新其绑定的所有项的列表。
<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基于**方法1 。