Правильно ли вызывать метод внутри Property Setter? - PullRequest
0 голосов
/ 24 мая 2019

В приложении WPF, над которым я работаю, я наткнулся на следующий фрагмент кода:

public int SomeInteger
{
    get { return _someInteger; }
    set
    {
        _someInteger= value;
        OnPropertyChanged("SomeInteger");
        SomeIntegerChanged();
    }
}

Как видите, внутри метода установки свойств вызывается метод.Является ли этот подход правильным или есть ли лучший способ сделать это в шаблоне MVVM WPF?

. Как показано выше, фрагмент кода является примером, фактически установщик свойств может загрузить DataTable, когда свойство изменяется, что может занять много времени.,Я пытался сделать приложение асинхронным, используя async и await, но вышеприведенные сценарии вызывают проблемы, поскольку async и await не имеют концепции асинхронных свойств.

Я также нашел способ привязкисобытие на INotifyPropertyChanged и проверяя, какое свойство вызывает событие и вызывает метод.Но ищу любые другие альтернативы.

Ответы [ 4 ]

5 голосов
/ 24 мая 2019

Является ли этот подход правильным или есть ли лучший способ сделать это в шаблоне MVVM WPF?

Это, к сожалению, распространенный и принятый шаблон MVVM во всем C #.Я говорю «к сожалению», потому что этот шаблон действительно сталкивается с проблемами.Он основан на событиях - которые сами по себе проблематичны - и он также вызывает немедленное обновление , что во многих случаях нежелательно.

Для одного примера иногда желательноимеют два свойства, которые взаимозависимы - когда пользователь меняет одно, другое изменяется по отношению к нему - и это может вызвать проблемы, поскольку нет никакого способа отличить «пользовательские изменения» от «изменений кода».

В другом примере иногда вы можете получить целое дерево зависимых свойств, и может потребоваться некоторое время, чтобы все изменения распространились и перестали мешать друг другу.

Более современные подходы MVVM, такие как атомно-обновленный единый источник истины с однонаправленным потоком данных (популяризированный Redux) позволяет избежать вышеуказанных проблем.Существует реализация C # Redux;Я не знаю, как легко это использовать.В моей собственной библиотеке CalculatedProperties я построил свою собственную "очередь недействительности", чтобы обойти это, что откладывает все PropertyChanged обновления до тех пор, пока не будет рассчитано новое устойчивое состояние всей системы.

Я пытался сделать приложение асинхронным, используя async и await, но приведенные выше сценарии вызывают проблемы, поскольку async и await не имеют концепции асинхронных свойств.

True.В частности, вы не можете «асинхронно получить» свойство.И это имеет смысл в мире MVVM;когда WPF обновляет экран и запрашивает у вашей виртуальной машины значение данных, тогда ваша виртуальная машина не может сказать «подождите, я получу это через минуту».WPF должен знать это значение сейчас , чтобы он мог обновлять экран сейчас .

Подключение обработчика асинхронных событий - это один из способов запустить асинхронную работу, когда значениеизменения;такой подход в порядке.Обычно наличие SomeIntegerChanged подразумевает, что есть «измененное» событие специально для этого свойства , поэтому, вероятно, труднее сделать это, подключившись к PropertyChanged с помощью сравнения строк.

Подробнее об асинхронных свойствах с MVVM см. Мою статью на тему .

2 голосов
/ 24 мая 2019

Установщик свойств не должен запускать длительную операцию.Следует просто установить значение вспомогательного поля и, возможно, вызвать быстрый синхронный метод, который возвращает почти сразу.Пожалуйста, обратитесь к @Stephen Cleary's сообщению в блоге для получения дополнительной информации.

Если вам нужно вызывать асинхронный всякий раз, когда устанавливается SomeInteger, вы можете, например, подключить обработчик событий asyncдля события PropertyChanged, например:

this.PropertyChanged += async (s, e) =>
{
    if (e.PropertyName == nameof(SomeInteger))
    {
        await SomeAsyncMethod();
    }
};
2 голосов
/ 24 мая 2019

В этом случае вызов методов в установщике - это нормально.Использование INotifyPropertyChanged для уведомлений об изменениях свойств в WPF является правильным способом, и добавление вызова в Setter является способом реализации по умолчанию.

Вызов SomeIntegerChanged(); зависит немного от того, что делает метод(и если это даже требуется, если вы уже реализовали INotifyPropertyChanged).

Использование свойств в качестве потребителя должно иметь как можно меньше побочных эффектов и, как правило, должно быть простыми операциями.На эту тему есть хорошее руководство по MSDN .

Вам также следует избегать использования строк имен свойств в качестве параметров, в вашем случае вызов OnPropertyChanged должен выглядеть следующим образом: OnPropertyChanged(nameof(SomeInteger));

0 голосов
/ 24 мая 2019

Я бы предостерег от преждевременной оптимизации.

Не усложняйте свое решение больше, чем необходимо.

Если изменение происходит немедленно, нет проблем с тем, чтобы поместить то, что вам нравится, в сеттер.

Зависимые изменения свойств являются случайным требованием, но также обычно не имеют большого значения.

Если у вас есть длительный процесс, который нужно запустить, это звучит так, как будто это должно быть нечто дискретное. Вы должны начать эту обработку в отдельном потоке и / или отделить обработку. Вы можете просто запустить огонь и забыть нить (не очень элегантно).

Вы можете отделить обработку, используя сервисные вызовы, очереди сообщений, такие как msmq или RabbitMQ или pub sub. Есть много подходов sub sub - простая реализация, являющаяся мессенджером mvvmlight или даже тегом-регистратором призмы. Более сложным будет NServiceBus или даже Windows Workflow. Если речь идет о событиях, то слабые события предпочтительнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...