WPF MVVM Правильный способ вызвать событие при просмотре из ViewModel - PullRequest
20 голосов
/ 28 апреля 2009

В моем приложении WPF у меня есть 2 Windows (обе Windows имеют собственную ViewModel):

  1. Главное окно приложения, в котором отображается список с набором слов (привязан к MainViewModel)

  2. Диалоговое окно, которое позволяет пользователям добавлять новые элементы в список (привязанный к AddWordViewModel)

MainViewModel имеет свойство Articles List (эта коллекция заполняется одним из классов обслуживания), привязанное к ListBox главного окна

В AddWordViewModel есть команда SaveWordCommand, связанная с кнопкой «Добавить диалог Word». Его задача - взять введенный пользователем текст и передать его в класс обслуживания.

После того, как пользователь нажал на кнопку Сохранить, мне нужно уведомить MainViewModel, чтобы перезагрузить Статьи из сервиса.

Моя идея состояла в том, чтобы выставить открытую команду в MainViewModel и выполнить ее из AddWordViewModel

Как правильно это реализовать?

Спасибо!

1 Ответ

18 голосов
/ 28 апреля 2009

Агрегаторы событий - неплохой способ решения проблемы такого типа. По сути, существует централизованный класс (для простоты, скажем, это Singleton, которому грозит возможный гнев анти-синглтонов), который отвечает за передачу событий от одного объекта к другому. С именами ваших классов использование может выглядеть так:

public class MainViewModel
{
    public MainViewModel()
    {
        WordAddedEvent event = EventAggregator.Instance.GetEvent<WordAddedEvent>();
        event.Subscribe(WordAdded);
    }

    protected virtual void WordAdded(object sender WordAddedEventArgs e)
    {
        // handle event
    }
}

public class AddWordViewModel
{    
    //From the command
    public void ExecuteAddWord(string word)
    {
        WordAddedEvent event = EventAggregator.Instance.GetEvent<WordAddedEvent>();
        event.Publish(this, new WordAddedEventArgs(word));
    }
}

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


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


Хорошо, последняя мысль. Перечитывая ваш вопрос, я вижу, что у вас уже есть какой-то класс Word Service, который обрабатывает поиск и хранение объектов Word. Нет причины, по которой служба не может нести ответственность за возникновение события при добавлении нового слова, поскольку обе ViewModels уже связаны с ним. Хотя я бы по-прежнему предположил, что EventAggregator является более гибким и лучшим решением, но здесь может применяться YAGNI

public class WordService
{
    public event EventHandler<WordAddedEventArgs> WordAdded;

    public List<string> GetAllWords()
    {
        //return words
    }

    public void SaveWord(string word)
    {
        //Save word
        if (WordAdded != null) WordAdded(this, new WordAddedEventArgs(word));
        //Note that this way you lose the reference to where the word really came from
        //probably doesn't matter, but might
    }
}

public class MainViewModel
{
    public MainViewModel()
    {
        //Add eventhandler to the services WordAdded event
    }
}

Чего вам следует избегать, так это введения связи между ViewModel, которые вы создадите, вызывая команду на одной ViewModel с другой, это сильно ограничит ваши возможности по расширению приложения (что если вторая ViewModel заинтересовалась другими словами, теперь обязанность AddWordViewModel сказать об этом тоже?)

...