如何在ViewModels之间进行通信?

时间:2014-04-18 18:37:59

标签: c# wpf mvvm viewmodel

我正在构建我的第一个WPF和MVVM应用程序。我有3个视图(有3个对应的ViewModels)

  

1)MainWindow(窗口)

     

2)ViewClients(UserControl)

     

3)ViewModClient(UserControl)

在客户端ViewModel中,我有一个属性 SelectedClient ,用于跟踪视图中DataGrid上的选定客户端。在这个视图中,我还有一个与MainWindow ViewModel中定义的ICommand相关的按钮。 我用这个绑定来解决它:

Command="{Binding Path=DataContext.CreateViewsCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" CommandParameter={x:Type local:ViewModClient}

我使用CommandParameter告诉mainWindow ViewModel创建哪种视图并保持viewmodel与视图知识隔离。这非常有效。

现在出现问题:

在ModClient ViewModel中,我需要加载客户端的数据。那么如何在保持MVVM模式的同时将其与客户端视图中的 SelectedClient 联系起来呢? (我只能使用一个CommandParameter并且它已经使用过了)

2 个答案:

答案 0 :(得分:1)

通常,这是通过使用消息传递来完成的。

所有MVVM框架都有一个消息传递总线,允许进行VM间通信,因此只需获得一个好的框架,任务就会变得如此简单(Simple MVVM Toolkit):

源VM:

SendMessage(MessageTokens.SomeToken, new NotificationEventArgs<string>
            (MessageTokens.SomeToken, "MyMessage"));

接收VM:

RegisterToReceiveMessages<string>(MessageTokens.SomeToken, OnMessageReceived);

private void OnMessageReceived(object sender, NotificationEventArgs<string> e)
{
    // Code to execute upon message reception.
}

答案 1 :(得分:1)

例如,Caliburn.Micro有一个内置的IEventAggregator,它允许你创建可以订阅的Eventmanagers。如果您使用多个ViewModel订阅此特定EventAggegrator,则可以定义可以从已订阅此EventAggregator的所有ViewModel发布和接收的消息。

以下只是一个简短的实现,并显示,如果您使用像Caliburn.Micro这样的框架,ViewModel之间的通信会有多简单:

class ViewModel1 : PropertyChangedBase
{
    private IEventAggregator _Event;
    public ViewModel1(IEventAggregator events)
    {
        _Event = events;
        _Events.Publish(new TestEvent(5));
    }
}

class ViewModel2 : PropertyChangedBase, IHandle<TestEvent>
{
    private IEventAggregator _Events;
    public ViewModel2(IEventAggregator events)
    {
        _Events = events;
        _Events.Subscribe(this);
    }

    public void Handle(TestEvent message)
    {
        // do something with the incoming message
    }
}

class TestEvent
{
    public int foo { get; set; }
    public TestEvent(int someint)
    {
        foo = someint;
    }
}

它应该是非常自我解释的。但是,如果您有任何疑问,请告诉我,我会详细介绍。