假设我有一个 WPF TextBox
:
<TextBox Text="{Binding Foo}" />
有没有办法ICommand
在属性Foo
更新后执行一些TextBox
(即由TextBox
而不是其他一些控件或代码专门更新)?
我不想使用绑定的 SourceUpdated 事件,因为我想避免“代码隐藏”。
你确实意识到如果最终有一些代码落后,MVVM 警察不会来抓你吗?使用事件来命令等本质上只是在 XAML 中编码,而不是在 C# 中。无论哪种方式,您都需要将事件与命令挂钩,因为控件不会公开您所追求的命令。
我认为这就是您所追求的,如果我走错了路,请告诉我:
您想知道对 Foo 的更新何时来自文本框并且仅来自文本框。即,如果对 Foo 的更新来自您不希望命令运行的某些代码,对吗?
如果是这样:
<TextBox Name="Fred" Text="{Binding Foo, NotifyOnSourceUpdated=True}" SourceUpdated="Fred_SourceUpdated"/>
然后在“邪恶”的代码后面有:
private void Fred_SourceUpdated(object sender, DataTransferEventArgs e)
{
}
在该方法中,您可以将视图的数据上下文转换为视图模型并调用您想要的任何命令。如果其他东西更新了 Foo,则不会调用源更新事件。
如果你真的不想像你在 OP 中提到的那样有代码,那么你可以做一个附加的行为,但这对于“无意义”的要求来说是巨大的矫枉过正。您的逻辑取决于更改是否来自文本框这一事实意味着您的视图已经不仅仅是一个视图。这种方法仍然允许您让您的命令代码在您的 VM 中完全可测试。
第二次编辑
您还可以通过事件命令而不是文本更改来查看在 XAML 中使用源更新事件
您可以尝试创建一个方法来执行您想做的任何事情,并在调用 raisepropertychanged() 之后调用该方法。例如
public void MyMethod()
{
//Do whatever;
}
然后在你的属性 getter setter 中:
public string MyText
{
get { return _MyText; }
set
{
_MyText = value;
RaisePropertyChanged("MyText")
// THen call that method
MyMehtod();
}
}
语法可能会关闭,我最近习惯做 vb。希望这会有所帮助,但如果您需要其他选择,还有其他方法。
编辑2:
<Textbox Text="{Binding Foo}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding TextChangedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
TextChangedCommand 在您的视图模型中的位置
不确定 TextChanged 是否为 EventName,我不记得所有可用的事件类型
假设你已经实现INotifyPropertyChanged
了,你只需要处理PropertyChanged
事件。您在事件处理程序中执行命令。此事件处理程序进入您的 ViewModel(而不是您的代码)。
编辑
这是 MVVM Light 中的 EventToCommand 行为如何工作的示例。您可以使用它允许使用命令处理任何事件。
<Rectangle Fill="White"
Stroke="Black"
Width="200"
Height="100">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseEnter">
<cmd:EventToCommand Command="{Binding TestCommand,
Mode=OneWay}"
CommandParameter="{Binding Text,
ElementName=MyTextBox,
Mode=OneWay}"
MustToggleIsEnabledValue="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
编辑 2
另一个想法是在Foo
通过代码更改时始终使用方法。这样,您就知道任何Foo
不使用该方法的更改都必须由用户更改。
private bool _isFooUpdating;
private void SetFoo(string value)
{
_isFooUpdating = true;
Foo = value;
_isFooUpdating = false;
}
public string Foo
{
get { return _foo; }
set
{
if (_foo = value) return;
_foo = value;
OnFooChanged();
OnPropertyChanged("Foo");
}
}
private void OnFooChanged()
{
if (_isFooUpdating) return;
FooChangedCommand.Execute();
}