MVVMLight - Messenger

Messenger

Mvvm提倡View和ViewModel的分离,View只负责数据的显示,业务逻辑都尽可能放到ViewModel中,
保持View.xaml.cs中的简洁(没有任何代码,除了构造函数),但是某些场景下也不必一定要保持
View.xaml.cs中的简洁,例如动画。我们想要让界面酷炫一点,就需要故事版,故事版中必然有与
控件相关的,动画和界面耦合很紧,并且也没有办法分离(或许有呢),我们大可直接将动画的逻辑
就放置到View的后台代码中,动画的触发条件由ViewModel发出,这里我们就要借助Messenger来完成
消息的传递。不仅View和ViewModel可以通过消息传递,ViewModel和ViewModel也需要通过消息传递
来完成一些交互。

Messenger的使用首先要注册消息,消息的标志是什么,消息接受的参数是什么,收到消息后执行什么
操作,然后是发送消息,向哪个消息发送信息,参数是什么。使用上和事件的订阅,事件的触发是一样的。

ViewModel之间通信

这个例子中,我们打开两个窗口(注意是同一个程序中,当初接触的时候不了解其原理,以为是Windows通信
机制中的消息通信,还傻傻的打开两个Application,让他们通信),窗口2向窗口1发送消息,窗口1显示接受到的消息。

我们先来看窗口1是怎么注册消息的
AppView1.xaml

<Window x:Class="MessengerDemo.Views.AppView1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MessengerDemo.Views" DataContext="{Binding Source={StaticResource Locator},Path=View1}"
    mc:Ignorable="d"
    Title="AppView1" Height="300" Width="300">
<Grid>
    <TextBlock Text="{Binding Msg}"></TextBlock>
</Grid>
</Window>

AppView1Model.cs

public class AppView1Model : ViewModelBase
{
    private string _msg;

    public string Msg
    {
        get
        {
            return _msg;
        }
        set
        {
            _msg = value;
            RaisePropertyChanged(() => Msg);
        }
    }

    public AppView1Model()
    {
        Messenger.Default.Register<string>(this, MessageToken.SendMessageToken, (msg) =>
        {
            Msg = msg;
        });
    }
}

注意:这里使用了一个静态类MessageToken,它的作用是定义消息标志,也是通过它区分不同的消息
MessageToken.cs

public static class MessageToken
{
    /// <summary>
    /// 动画信息标志
    /// </summary>
    public static readonly string AnimateMessageToken;

    /// <summary>
    /// 发送消息标志
    /// </summary>
    public static readonly string SendMessageToken;

    static MessageToken()
    {
        AnimateMessageToken = nameof(AnimateMessageToken);

        SendMessageToken = nameof(SendMessageToken);
    }
}

这里定义了2个消息类型,一个用于动画演示,一个用于发送消息。

我们再来看窗口2是怎么发送消息的
AppView2.xaml

<Window x:Class="MessengerDemo.Views.AppView2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MessengerDemo.Views" DataContext="{Binding Source={StaticResource Locator},Path=View2}"
    mc:Ignorable="d"
    Title="AppView2" Height="300" Width="300">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <TextBox Text="{Binding Msg}"></TextBox>

    <Button Width="100" Height="30" Grid.Row="1" Content="Send" Command="{Binding SendCommand}"></Button>
</Grid>
</Window>

AppView2Model.cs

public class AppView2Model : ViewModelBase
{
    private string _msg;

    public string Msg
    {
        get
        {
            return _msg;
        }
        set
        {
            _msg = value;
            RaisePropertyChanged(() => Msg);
        }
    }

    public RelayCommand SendCommand
    {
        get; set;
    }

    public AppView2Model()
    {
        SendCommand = new RelayCommand(() =>
          {
              Messenger.Default.Send<string>(Msg, MessageToken.SendMessageToken);
          });
    }
}

这里使用的是同一个MessageToken,这样调试的时候也方便查找。这里我们发送消息时,传递的参数是字符串,
这里可以传递任何类型。

View和ViewModel之间通信

在来看一个动画的,动画的逻辑都写到了View的后台代码中,ViewModel发送触发动画的消息

AppView1.xaml

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <TextBlock Text="{Binding Msg}"></TextBlock>

    <Button Width="100" Height="30" Grid.Row="1" Content="执行动画" x:Name="btn" Command="{Binding AnimateCommand}">
        <Button.RenderTransform>
            <TransformGroup>
                <ScaleTransform/>
                <SkewTransform/>
                <RotateTransform/>
                <TranslateTransform/>
            </TransformGroup>
        </Button.RenderTransform>
    </Button>
</Grid>

AppView1.xaml.cs

public partial class AppView1 : Window
{
    private Storyboard _storyboard;

    public AppView1()
    {
        InitializeComponent();

        _storyboard = new Storyboard();

        DoubleAnimation doubleAnimation = new DoubleAnimation(0, 180, new Duration(new TimeSpan(0, 0, 2)));
        Storyboard.SetTarget(doubleAnimation, btn);
        Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"));

        _storyboard.Children.Add(doubleAnimation);

        Messenger.Default.Register<string>(this, MessageToken.AnimateMessageToken, (msg) =>
         {
             _storyboard.Begin();
         });
    }
}

AppView1Model.cs

public class AppView1Model : ViewModelBase
{
    public RelayCommand AnimateCommand
    {
        get; set;
    }

    public AppView1Model()
    {
        AnimateCommand = new RelayCommand(() =>
          {
              Messenger.Default.Send<string>("", MessageToken.AnimateMessageToken);
          });
    }
}

当然,动画还是使用Blend编写要舒服一些。有了Messenger,使得ViewModel和ViewModel之间一定的
解耦,可以处理更复杂的情况。

时间: 2024-08-30 05:12:37

MVVMLight - Messenger的相关文章

MvvmLight框架使用入门(四)

本篇我们着重介绍ViewModelBase,演示Set和RaisePropertyChanged方法的使用,以及就Cleanup方法释放资源展开讨论. ICleanup 接口.实现该接口的ViewModel需要在Cleanup方法里释放资源,特别是-= event ObservableObject 该类实现了INotifyPropertyChanged接口,定义了一个可通知的对象基类,供ViewModelBase继承 ViewModelBase 继承自ObservableObject,   IC

[uwp]MVVM之MVVMLight,一个登录注销过程的简单模拟

之前学MVVM,从ViewModelBase,RelayCommand都是自己瞎写,许多地方处理的不好,接触到MVVMLigth后,就感觉省事多了. 那么久我现在学习MVVMLight的收获,简单完成以下一个Demo Demo主要功能是: 用户在登录界面登陆,登录成功后跳转到另一个页面,同时把登录时的用户信息作为参数传递过去,然后用户可以选择注销,注销时会弹出对话框,让用户选择是否真的注销,如果是,就真的注销,回退到       登录页面,否则就不做任何处理. 功能很简洁,接下来就用MVVMLi

利刃 MVVMLight

已经很久没有写系列文章了,上一次是2012年写的HTLM5系列,想想我们应该是较早一批使用HTML5做项目的人. 相比我当时动不动100+的粉丝增长和两天3000+的阅读量,MVVM Light只能算小众技术了,也是因为她小众,才更具意义,不希望有人跟我一样网上找案例找半天. 写的初衷也是希望同项目组的同事能更好的融入和接收已有项目.其中两篇<DispatchHelper在多线程和调度中的使用>和<Messenger>是在上林院长课的时候抱着笔记本写的,现在想想挺后悔的, 再回头上

管窥MVVMLight Command参数绑定和事件传递

前言 由于在实际项目中,业务功能的增加导致软件开发规模在逐渐变大,所以我准备找个Silverlight框架来组织当前项目中的文件,以期能够让后续的业务功能增添和维护更加容易一些.无意中,我在这篇文章中看到了当前Silverlight下所有的框架的评测:Discover and compare existing MVVM frameworks !,当我看到MvvmLight toolkit在各方面都比较完备的时候,于是决定选择这个框架: 在Codeplex网站上,下载了MVVM Light Too

Messenger和MVVM中的View Services

在前面的文章IoC容器和MVVM中, 介绍了IoC容器如何在大量用户类中帮助创建和分配用户类的实例.本文将介绍IoC容器如何帮助应用程序解耦,比如那些根据MVVM模式开发的应用.此模 式广泛应用在基于XAML的应用程序(Silverlignt, WPF, Windows Phone, Windows 8)中,因为此模式与数据绑定系统和用于这类程序设计的工具匹配的很好,尤其是在VS 设计器和Blend中. 在典型的XAML程序中,开发者利用数据绑定系统声明一个XAML UI元素的属性和应用程序中其

关于 MVVMLight 设计模式系列

MVVM设计模式你可以在WPF.Silverlight.Windows Phone开发中使用,我想至今已经有非常非常多的朋友正在使用MVVM设计模式,尤其是MVVMLight . 本系列文章以WPF举例,似乎在百度上如果你要查找MVVM相关的某个知识点,难点,给我的感觉资料是比较少的.本篇文章是一个目录导航,我会在最 近一段时间把相关的MVVMLight的知识与技巧发布在我的博客中,并在本文中以目录的方式呈现.希望能为业界贡献一份微薄之力,帮助到正在看此文的 你. 有不足之处还望各位Coder们

Messenger 深入

1.Messager交互结构和消息类型 衔接上篇,Messeger是信使的意思,顾名思义,他的目是用于View和ViewModel 以及 ViewModel和ViewModel 之间的消息通知和接收. Messenger类用于应用程序的通信,接受者只能接受注册的消息类型,另外目标类型可以被指定,用Send<TMessage, TTarget>(TMessage message)实现,在这种情况下信息只能被传递如果接受者类型和目标参数类型匹配, message可以是任何简单或者复杂的对象,你可以

使用 MVVMLight 消息通知

欢迎阅读我的MVVMLight教程系列文章<关于 MVVMLight 设计模式系列> 在文章的其实我们就说了,MVVMLight的精华就是消息通知机制,设计的非常不错.这个东西在MVVMLight可以说是用的及其的频繁,当 ViewModel请求View要有些改变的时候(比如弹个窗体)那么你在ViewModel里面编写弹窗的代码?那也就违背了MVVM的设计模式 啦,MVVMLight的消息通知可以实现互相调用代码而不耦合! 如何使用 MVVMLight 消息通知 接着我们上一篇文章的项目,也说

MvvmLight学习篇—— Mvvm Light Toolkit for wpf/silverlight系列(导航)

一.Mvvm Light Toolkit for wpf/silverlight系列之准备工作 二.Mvvm Light Toolkit for wpf/silverlight系列之搭建mvvmlight开发框架 三.Mvvm Light Toolkit for wpf/silverlight系列之数据绑定 四.Mvvm Light Toolkit for wpf/silverlight系列之Command和Events 五.Mvvm Light Toolkit for wpf/silverli