WPF MVVM从ViewModel在视图上触发事件的正确方法

Dan*_*rik 20 .net wpf binding command mvvm

在我的WPF应用程序中,我有2个Windows(两个Windows都有自己的ViewModel):

  1. 应用程序的主窗口,显示带有一堆单词的列表(绑定到MainViewModel)

  2. 允许用户将新项添加到列表中的对话窗口(绑定到AddWordViewModel)

MainViewModel具有List的Items属性(此集合由其中一个服务类填充)绑定到Main Window的ListBox

AddWordViewModel具有绑定到"添加单词对话框"的"保存"按钮的SaveWordCommand.它的任务是获取用户输入的文本并将其传递给服务类.

用户单击"保存"按钮后,我需要通知MainViewModel从服务中重新加载文章.

我的想法是在MainViewModel中公开public命令并从AddWordViewModel执行它

实施它的正确方法是什么?

谢谢!

Mar*_*ris 19

事件聚合器是解决此类问题的一种很好的方法.基本上有一个集中的类(为了简单起见,让我们说它是一个单身人士,并面对反单身人士可能的愤怒),负责将事件从一个对象转移到另一个对象.使用您的类名,用法可能如下所示:

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

这种模式的优点是,您可以非常轻松地扩展您的应用程序,使其具有多种创建单词的方式,以及对已添加的单词感兴趣的多个ViewModel,两者之间没有耦合,因此您可以添加和删除它们需要.


如果你想避免使用单例(并且出于测试目的,我建议你这样做),那么可能值得研究依赖注入,尽管这确实是另一个问题.


好的,最后的想法.我从重新阅读你的问题看到你已经有了某种Word Service类来处理Word对象的检索和存储.由于两个ViewModel已经连接到新单词,因此没有理由在添加新单词时服务不负责引发事件.虽然我仍然建议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
    }
}
Run Code Online (Sandbox Code Playgroud)

你要避免做的是引入ViewModel之间的耦合,你将通过在一个ViewModel上调用命令来创建另一个,这将严重限制你扩展应用程序的选项(如果第二个ViewModel对新单词感兴趣会怎样) ,现在AddWordViewModel有责任告诉那个吗?)