在MVVM中,如何区分视图模型的用户更改和系统更改?

时间:2018-10-15 16:46:49

标签: c# mvvm mvvm-light

我发现,定义视图模型的常用方法无法区分用户的更改和系统的更改。例如,

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,这将导致事件SourceUpdatedTextBox更新绑定时触发。然后,当发生此事件时,我可以调用命令:

<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事件而更新视图之外)。

0 个答案:

没有答案