假设有这样一个需求,有这样一个聊天界面,主界面是选项卡,其一选项卡内部是真正的聊天列表和聊天界面,我们需要实时的在主界面显示未读消息的数量

假设我们已经有方法可以拿到未读消息的数量,那么如何在主界面的选项卡上面进行显示呢,如钉钉

第一,我们可以很暴力的直接在子控件的viewmodel或者后台代码中拿到主界面中绑定的一个属性值,直接进行修改。这种方法很简单,很方便,但是在程序内部无疑增加了耦合度

刚毕业或工作一年的这样写我觉得可以,但是如果你是个有程序洁癖并且有了一定工作经验的程序员的话,你肯定很不爽。你可能会去百度看看别人是如何做的,其实你也很容易就能得到一些方案,比如MVVMLight自带的通信机制就是很好的选择,但是它很重,如果你的MVVM不是使用的它的话,那你为了这点功能而且选择使用它,其实很浪费,并且它的通信功能很强大,如果你的需求仅仅和文章开头差不多或者稍微复杂点则完全没必要。

第二,我们则自己尝试制作这样一个消息通信中心。

思考几分钟,首先,观察者模式充斥着我们的桌面开发中,利用发布/订阅这种模式,显示最合理也最简单,在面向事件开发中,订阅事件,将我们的动作绑定到事件上,触发事件同时调用我们的动作,则整个过程也顺利完成。

1.完成带有消息存储和发布/订阅的事件处理中心

我们使用键值对将我们的消息和事件进行绑定,并且完成发布/订阅两个方法,这里的方法会对所有订阅者进行发布,如果需要分组,过滤,多次执行等操作,可以重写该类及发布订阅方法。

public class Messager
{
/// <summary>
/// 消息集合
/// </summary>
private IDictionary<string, MessagerInvokeHandler> Messagers =
new Dictionary<string, MessagerInvokeHandler>(); private Messager() { } private static Messager _message; public static Messager Default => _message??(_message=new Messager()); /// <summary>
/// 订阅
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="topic"></param>
/// <param name="t"></param>
public virtual void Register<T>(string topic,Action<MessagerContext> t)
{
if (t == null)
throw new ArgumentException();
if (Messagers.ContainsKey(topic))
{
var value=Messagers.FirstOrDefault(o => o.Key == topic).Value;
value.MessagerInvokeEvent += t;
return;
}
var invoker=new MessagerInvokeHandler();
invoker.MessagerInvokeEvent += t;
Messagers.Add(topic, invoker);
} /// <summary>
/// 发布
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="topic"></param>
/// <param name="element"></param>
public virtual void Send<T>(string topic, T element)
{
if (!Messagers.ContainsKey(topic))
return;
var invoker = Messagers.FirstOrDefault(o => o.Key == topic).Value;
invoker.Invoke(new MessagerContext()
{
Data=element,
Topic=topic
});
}
}

2.发布消息时的事件处理类

包含一个事件用来绑定订阅的操作,以及一个方法执行事件

/// <summary>
/// 消息执行类
/// </summary>
public class MessagerInvokeHandler
{
public event Action<MessagerContext> MessagerInvokeEvent; public void Invoke(MessagerContext context)
{
MessagerInvokeEvent.Invoke(context);
}
}

3.消息调用时的上下文参数

这边大家可以根据自己的需求自行增加修改

public class MessagerContext
{
/// <summary>
/// 消息体
/// </summary>
public object Data { get; set; } /// <summary>
/// 主题
/// </summary>
public string Topic { get; set; }
}

如何使用?

订阅

//注册修改单个消息的通知
Messager.Default.Register<Int32>(MessagerTopic.ModifySingleCount, ModifySingleCount);        private void ModifySingleCount(MessagerContext context)
  {
  。。。。
  }

发布

Messager.Default.Send<Int32>(MessagerTopic.ModifySingleCount,10);

我已经在项目中使用该方法了,但是又缺陷就是设计问题,导致上下文没有使用泛型,data只能用object类型接收,有任何问题欢迎指正!

WPF 组件间通信 MVVM 进行解耦的更多相关文章

  1. 聊聊Vue.js组件间通信的几种姿势

    写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出. 文章的原地址:https://github.com/a ...

  2. React独立组件间通信联动

    React是现在主流的高效的前端框架,其官方文档 http://reactjs.cn/react/docs/getting-started.html 在介绍组件间通信时只给出了父子组件间通信的方法,而 ...

  3. 【Vue】利用父子组件间通信实现一个场景

    组件间通信是组件开发的,我们既希望组件的独立性,数据能互不干扰,又不可避免组件间会有联系和交互. 在vue中,父子组件的关系可以总结为props down,events up: 在vue2.0中废弃了 ...

  4. React 精要面试题讲解(二) 组件间通信详解

    单向数据流与组件间通信 上文我们已经讲述过,react 单向数据流的原理和简单模拟实现.结合上文中的代码,我们来进行这节面试题的讲解: react中的组件间通信. 那么,首先我们把看上文中的原生js代 ...

  5. vue_组件间通信:自定义事件、消息发布与订阅、槽

    自定义事件 只能用于 子组件 向 父组件 发送数据 可以取代函数类型的 props 在父组件: 给子组件@add-todo-event="addTodo" 在子组件: 相关方法中, ...

  6. Vue的父子组件间通信及借助$emit和$on解除父子级通信的耦合度高的问题

    1.父子级间通信,父类找子类非常容易,直接在子组件上加一个ref,父组件直接通过this.$refs操作子组件的数据和方法    父 这边子组件中 就完成了父 => 子组件通信 2. 子 =&g ...

  7. React 组件间通信介绍

    React 组件间通信方式简介 React 组件间通信主要分为以下四种情况: 父组件向子组件通信 子组件向父组件通信 跨级组件之间通信 非嵌套组件间通信 下面对这四种情况分别进行介绍:   父组件向子 ...

  8. Vue 根组件,局部,全局组件 | 组件间通信,案例组件化

    一 组件 <div id="app"> <h1>{{ msg }}</h1> </div> <script src=" ...

  9. [转] React 中组件间通信的几种方式

    在使用 React 的过程中,不可避免的需要组件间进行消息传递(通信),组件间通信大体有下面几种情况: 父组件向子组件通信 子组件向父组件通信 跨级组件之间通信 非嵌套组件间通信 下面依次说下这几种通 ...

  10. React的组件间通信

    一.React的单向数据流 React是单向数据流,数据主要从父节点传递到子节点(通过props).如果顶层(父级)的某个props改变了,React会重渲染所有的子节点.这通常被称为“自顶向下”或“ ...

随机推荐

  1. 《AI驱动下的开发者新生态》-2024长沙.NET技术社区活动-诚邀大家报名

    回顾 2019年初,在.NET中文社区及包括苏州.广州.深圳等地区社区等大力推动.在众多企业的大力支持下,长沙地区的开发者们发起成立了长沙.NET技术社区,并组织了<2019年长沙开发者技术大会 ...

  2. B3610 [图论与代数结构 801] 无向图的块 题解

    题目传送门 前言 本题解内容均摘自我的 Tarjan 学习笔记 . 解法 Tarjan 与无向图 无向图与割点(割顶) 在一个无向图中,不存在横叉边(因为边是双向的). 一个无向图中,可能不止存在一个 ...

  3. 详解instanceof底层原理,从零手写一个instanceof

    壹 ❀ 引 本道题的核心考点还是对于javascript原型的掌握程度,比如__proto__,prototype相关概念,以及instanceof底层原理的理解.若你对于原型已经非常熟悉,那么可以直 ...

  4. NC16697 [NOIP2001]Car的旅行路线

    题目链接 题目 题目描述 又到暑假了,住在城市A的Car想和朋友一起去城市B旅游.她知道每个城市都有四个飞机场,分别位于一个矩形的四个顶点上,同一个城市中两个机场之间有一条笔直的高速铁路,第I个城市中 ...

  5. Linux常用的20个命令(下)

    无论你是后端程序员还是前端程序员,都避免不了和Linux打交道.上篇介绍了Linux常用的20个命令其中的10个,本文继续介绍剩下的10个命令. 11.man 命令 manual的缩写,即使用手册的意 ...

  6. 盘点 Udemy 上最受欢迎的免费编程课程

    之前给大家推荐过一些油管上的免费学习资源,如果您还没有看过的话可以点击这里前往. 今天再给大家推荐一批Udemy上超高质量并且免费的编程课程,有需要的小伙伴可以学起来了. 1. JavaScript ...

  7. ubuntu16.04 ssh启用root连接

    安装好ubuntu16.04 server版默认是不允许客户端ssh工具连接root的. 启用方法如下: 1.设置root密码 dylan@ubuntu:~$ sudo passwd root [su ...

  8. SpringBoot整合ip2region实现使用ip监控用户访问地域来源

    举个栗子 最*,多*台都上线了展示*期发帖所在地功能,比如抖音.微博.百度,像下面那样: 那么这个功能都是如何实现的呢? 一般有两个方法:GPS 定位的信息和用户 IP 地址. 由于每个手机都不一定会 ...

  9. win32-StretchDIBits - PrintDlg

    使用StretchDIBits将位图数据传输到printer的dc中 #include <Windows.h> #include <algorithm> int main() ...

  10. 【Azure Cache for Redis】Redis的导出页面无法配置Storage SAS时通过az cli来完成

    问题描述 在Azure Redis的导出页面,突然不能配置Storage Account的SAS作为授权方式. 那么是否可以通过AZ CLI或者是Powershell来实现SAS的配置呢? 问题解答 ...