В MVVM как отличить пользовательские изменения от системных изменений в модели представления? - PullRequest
0 голосов
/ 15 октября 2018

Я обнаружил, что обычный способ определения моделей представлений не различает изменения пользователя и изменения системы.Например,

public class PersonViewModel : ViewModelBase
{
    private string _name;
    public string Name
    {
        get => _name;
        set => Set(ref _name, value);
    }
}

Здесь уведомление PropertyChanged будет сгенерировано, если пользователь изменит имя в представлении.Но оно также будет поднято, если приложение по какой-либо причине изменит свойство (например, во время инициализации или в качестве ответа на какое-либо событие).

Я могу захотеть ответить по-разному в зависимости от того, сделал ли пользователь изменениеили система внесла изменения.Например, я могу захотеть регистрировать только изменения, сделанные пользователем для целей аудита.

Приходилось ли другим делать это различие, и как вы его реализовали?

На данный момент,лучшее решение, которое я придумала, - это отправить сообщение, когда пользователь вносит изменение, но когда приложение должно внести изменение, оно должно вызвать метод установки:

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 возникает, так что представление обновляется независимо от того, сделал ли пользователь изменение или нет.Когда пользователь вносит изменения, я могу обработать сообщение, отправленное определенным образом (возможно, при выполнении конкретного варианта использования).Когда система вносит изменения, она просто обновляет представление.

Обновление: Я нашел возможное решение здесь .В случае 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).

...