WPF MVVM 从 ViewModel 触发事件的正确方法 [英] WPF MVVM Correct way to fire event on view from ViewModel

查看:89
本文介绍了WPF MVVM 从 ViewModel 触发事件的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my WPF application I have 2 Windows (both Windows have their own ViewModel):

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

  1. Application's Main Window that displays list with bunch of words (bound to MainViewModel)

允许用户向列表中添加新项目的对话框窗口(绑定到 AddWordViewModel)

Dialog Window that allows users add new items to the list (bound to AddWordViewModel)

MainViewModel 具有绑定到主窗口的 ListBox 的 List 的 Articles 属性(此集合由服务类之一填充)

MainViewModel has Articles property of List(this collection is populated by one of the service classes) bound to Main Window's ListBox

AddWordViewModel 有 SaveWordCommand,它绑定到 Add Word Dialog 的 Save 按钮.它的任务是将用户输入的文本传递给服务类.

AddWordViewModel has SaveWordCommand that is bound to Add Word Dialog's Save button. It's task is to take text entered by user and pass it to service class.

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

After user clicks on on Save button I need notify MainViewModel to reload Articles from service.

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

My idea was to expose public command in MainViewModel and execute it from AddWordViewModel

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

What is correct way to implement it?

谢谢!

推荐答案

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

Event Aggregators are quite a nice way of solving this type of problem. Basically there is a centralised class (for simplicities sake let's say it's a Singleton and face the possible wrath of the anti-singleton guys) that is responsible for transferring events from one object to another. With your class names the usage may look like:

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));
    }
}

这种模式的优点是你可以很容易地扩展你的应用程序以有多种创建单词的方式和多个对添加的单词感兴趣的ViewModels,并且两者之间没有耦合,因此您可以添加和删除根据需要使用它们.

The advantage of this pattern is that you can very easily expand your application to have multiple ways of creating words and multiple ViewModels that are interested in words that have been added and there is no coupling between the two so you can add and remove them as you need to.

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

If you want to avoid the singleton (and for testing purposes I would suggest you do) then it may be worth looking into dependency injection, though that really is a whole other issue.

好的,最后的想法.我从重新阅读您的问题中看到,您已经拥有某种 Word Service 类来处理 Word 对象的检索和存储.当添加新词时,服务没有理由不负责引发事件,因为两个 ViewModel 已经耦合到它.虽然我仍然建议 EventAggregator 更灵活和更好的解决方案,但 YAGNI 可能在这里申请

Okay, final thought. I see from re-reading your question that you already have some kind of Word Service class that handles the retrieval and storage of the Word objects. There is no reason that the service can't be responsible for raising the event when the new word is added since both ViewModels already are coupled to it. Though I'd still suggest the EventAggregator is more flexible and a better solution, but YAGNI may apply here

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 之间的耦合,这将严重限制您扩展应用程序的选项(如果第二个 ViewModel 感兴趣会怎样)换句话说,现在是不是 AddWordViewModel 也有责任告诉那个人?)

What you want to avoid doing though is introducing the coupling between ViewModels that you'll create by calling a command on one ViewModel with the other, this will severely limit your options for expanding the application (what if a second ViewModel became interested in new words, is it now the AddWordViewModel's responsibility to tell that one too?)

这篇关于WPF MVVM 从 ViewModel 触发事件的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆