我发现,定义视图模型的常用方法无法区分用户的更改和系统的更改。例如,
public class PersonViewModel : ViewModelBase
{
private string _name;
public string Name
{
get => _name;
set => Set(ref _name, value);
}
}
在此,如果用户在视图中更改名称,则将引发PropertyChanged通知。但是,如果应用程序由于某种原因(例如,在初始化期间或对某些事件的响应)更改属性,也会引起这种情况。
我可能想根据用户是进行更改还是系统进行更改来做出不同的响应。例如,我可能只想记录用户所做的更改以用于审核。
其他人必须做出这种区分,您是如何实现的?
目前,我想出的最佳解决方案是在用户进行更改时发送一条消息,但是当应用程序需要进行更改时,它应该调用setter方法:
public class PersonViewModel : ViewModelBase
{
private string _name;
public string Name
{
get => _name;
set
{
if (SetName(value))
MessengerInstance.Send(new SetNameRequest(this));
}
}
public bool SetName(string value) =>
Set(nameof(Name), ref _name, value);
}
在任何一种情况下,都会引发PropertyChanged事件,以便无论用户是否进行了更改都将更新视图。当用户进行更改时,我可以处理以某种方式发送的消息(也许执行特定的用例)。当系统进行更改时,它只会更新视图。
更新:我找到了可能的解决方案here。对于TextBox
,关键思想是将NotifyOnSourceUpdated
设置为True
,这将导致事件SourceUpdated
在TextBox
更新绑定时触发。然后,当发生此事件时,我可以调用命令:
<TextBox Text="{Binding Name, NotifyOnSourceUpdated=True}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SourceUpdated">
<i:InvokeCommandAction Command="{Binding SetNameCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
在我的视图模型中,我可以按照自己想要的任何方式来处理命令。就我而言,我发送一条消息,以便由适当的用例处理:
public class PersonViewModel : ViewModelBase
{
private string _name;
public string Name
{
get => _name;
set => Set(ref _name, value);
}
public ICommand SetNameCommand => new RelayCommand(() =>
MessengerInstance.Send(new SetNameRequest(this)));
}
通过这种方式,通过代码设置Name
属性将更新视图,但不会调用该命令。但是,如果用户通过Name
更改了TextBox
属性,则会调用并最终处理命令(除了由于引发PropertyChanged
事件而更新视图之外)。