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

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

问题描述

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


  1. 应用程序的主窗口(绑定到MainViewModel)


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

    li>

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



AddWordViewModel有SaveWordCommand,它绑定到Add Word对话框的Save按钮。



用户点击Save按钮后,我需要通知MainViewModel从服务中重新载入文章。 p>

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



什么是正确的实现方法?



谢谢!

解决方案

事件聚集器是解决这类问题的一个很好的方法。基本上有一个集中的类(为了简单起见,我们说它是一个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
{
//从命令
public void ExecuteAddWord(string word)
{
WordAddedEvent event = EventAggregator.Instance.GetEvent< WordAddedEvent>();
event.Publish(this,new WordAddedEventArgs(word));
}
}

这种模式的优点是,扩展你的应用程序有多种方式创建单词和多个ViewModel对已添加的单词感兴趣,并且两者之间没有耦合,所以你可以根据需要添加和删除它们。






如果你想避免单例(为了测试的目的,我建议你这样做),那么它可能值得研究依赖注入,一个整体的其他问题。






好的,最后的想法。我看到从重新阅读你的问题,你已经有一些类型的Word服务类处理Word对象的检索和存储。没有理由,当添加新单词时,服务不能负责提高事件,因为两个ViewModel已经耦合到它。虽然我仍然建议EventAggregator更灵活,更好的解决方案,但 YAGNI

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

public List< string> GetAllWords()
{
//返回字
}

public void SaveWord(string word)
{
//保存字
if(WordAdded!= null)WordAdded(this,new WordAddedEventArgs(word));
//注意,这样你就失去了这个词真正来自哪里的引用
//可能没有关系,但可能
}
}

public class MainViewModel
{
public MainViewModel()
{
//向服务添加事件处理程序WordAdded事件
}
}

你想避免做的是引入ViewModels之间的耦合,你将通过调用一个命令ViewModel与其他,这将严重限制您的选项扩展的应用程序(如果第二个ViewModel感兴趣的新词,如果现在是AddWordViewModel的责任,告诉那个)?


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

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

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

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

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.

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

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

What is correct way to implement it?

Thank You!

解决方案

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

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.


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

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天全站免登陆