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之间一定的

解耦,可以处理更复杂的情况。

Messenger的更多相关文章

  1. android:使用Messenger进行进程间通信(一)

    Messenger简介 Messenger和AIDL是实现进程间通信(interprocess communication)的两种方式. 实际上,Messenger的实现其实是对AIDL的封装. Me ...

  2. Android进程间通讯之messenger

    这两天在看binder,无意间在文档看到messenger这么个东西,感觉这个东西还挺有意思的,给大家分享一下. 平时一说进程间通讯,大家都会想到AIDL,其实messenger和AIDL作用一样,都 ...

  3. android 史上最简单易懂的跨进程通讯(Messenger)!

    不需要AIDL也不需要复杂的ContentProvider,也不需要SharedPreferences或者共享存储文件! 只需要简单易懂的Messenger,它也称为信使,通过它可以在不同进程中传递m ...

  4. android:使用Messenger进行进程间通信(二)

    //继续完善音乐播放器demo 相关文章: android:使用Messenger进行进程间通信(一):http://www.cnblogs.com/happyhacking/p/5318418.ht ...

  5. How secure FB Messenger is?

    It's reported that FB Messenge is the most secure App for instant messaging service. Let's see if FB ...

  6. Android进程间的通信之Messenger

    Android进程间的通信方式可以通过以下两种方式完成: Android接口定义语言(AIDL) 使用Messenger绑定服务 本文我们将学习使用Messenger绑定服务的方式进行进程间的通信. ...

  7. Android IPC机制之Messenger

    Messenger:两个进程通过Messenger传递消息,进程1和进程2中都需要创建一个Messenger,创建过程:首先进程2需要创建一个服务, 并在服务中创建一个Messenger对象,进程1通 ...

  8. Facebook Messenger的后台架构是什么样的?

    后台的架构是由前台的需求决定的.做 mobile app 的需求跟做 web app 是不一样的,比如 mobile app 对实时性的要求比较强(移动用户都没耐性),移动设备网络不稳定(要能做到断点 ...

  9. Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- Messenger

    Messenger类实际是对Aidl方式的一层封装.本文只是对如何在Service中使用Messenger类实现与客户端的通信进行讲解,对Messenger的底层不做说明.阅读Android Prog ...

随机推荐

  1. Ubuntu/Windows双系统修复引导

    Ubuntu/Windows双系统修复引导   首先说明:在Windows存在的前提下安装Ubuntu(或者Ubuntu系列)是不需要修复引导的.因为grub会自动搜索存在硬盘中的系统.   而在Ub ...

  2. javascript-建造者模式

    建造者模式笔记 1.工厂模式主要是为了创建对象实例或者类簇(抽象工厂),关心的是最终产出(创建)的是什么,不关心你创建的整个过程,仅仅需要知道你最终创建的结果 2.建造者模式目的也是为了创建对象,但是 ...

  3. Java并发工具类Semaphore应用实例

    package com.thread.test.thread; import java.util.Random; import java.util.concurrent.*; /** * Semaph ...

  4. 一篇博客理解Recyclerview的使用

    从Android 5.0开始,谷歌公司推出了RecylerView控件,当看到RecylerView这个新控件的时候,大部分人会首先发出一个疑问,recylerview是什么?为什么会有recyler ...

  5. EF Power Tools的Reverse Engineer Code First逆向生成Model时处理计算字段

    VS2013上使用EF Power Tools的Reverse Engineer Code First逆向生成Model时,没有处理计算字段.在保存实体时会出现错误. 可以通过修改Mapping.tt ...

  6. 【Oracle XE系列之一】Windows10_X64环境 安装Oracle XE11gR2 X64数据库

    一.安装 1.去Oracle官网下载XE版的安装包[下载路径](Oracle Database Express Edition 11g Release 2 for Windows x64),解压. 2 ...

  7. oops call trace 解析

    Call Trace: [  221.634988]  [<ffffffff8103fbc7>] ? kmld_pte_lookup+0x17/0x60 [  221.635016]  [ ...

  8. 编写NPAPI plugin的命名问题

    最近写了个NPAPI的插件,在chrome上用得好好的,结果在火狐上死活不认我的插件,找了N多资料最后在官方的说明里才找到说火狐浏览器的插件的文件名必须是以np开头的,立刻吐血三升,难怪被chrome ...

  9. Solr初始化源码分析-Solr初始化与启动

    用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究.但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机 ...

  10. 洛谷P1538迎春舞会之数字舞蹈

    题目背景 HNSDFZ的同学们为了庆祝春节,准备排练一场舞会. 题目描述 在越来越讲究合作的时代,人们注意的更多的不是个人物的舞姿,而是集体的排列. 为了配合每年的倒计时,同学们决定排出——“数字舞蹈 ...