【炫丽】从0开始做一个WPF+Blazor对话小程序( 八 )

IMessenger
消息接口 , 只定义了三个接口:

  1. Subscribe:消息订阅
  2. Unsubscribe:取消消息订阅
  3. Publish:消息发送
using System;namespace WPFBlazorChat.Messages;public interface IMessenger{void Subscribe<TMessage>(object recipient, Action<TMessage> action,ThreadOption threadOption = ThreadOption.PublisherThread) where TMessage : Message;void Unsubscribe<TMessage>(object recipient, Action<TMessage>? action = null) where TMessage : Message;void Publish<TMessage>(object sender, TMessage message) where TMessage : Message;}public enum ThreadOption{PublisherThread,BackgroundThread,UiThread}Messenger
消息的管理,消息中转等实现:
using System;using System.Collections.Generic;using System.Linq;using System.Threading;using System.Threading.Tasks;namespace WPFBlazorChat.Messages;public class Messenger : IMessenger{public static readonly Messenger Default = new Messenger();private readonly object registerLock = new object();private Dictionary<Type, List<WeakActionAndToken>>? recipientsOfSubclassesAction;public void Subscribe<TMessage>(object recipient, Action<TMessage> action, ThreadOption threadOption)where TMessage : Message{lock (this.registerLock){var messageType = typeof(TMessage);this.recipientsOfSubclassesAction ??= new Dictionary<Type, List<WeakActionAndToken>>();List<WeakActionAndToken> list;if (!this.recipientsOfSubclassesAction.ContainsKey(messageType)){list = new List<WeakActionAndToken>();this.recipientsOfSubclassesAction.Add(messageType, list);}else{list = this.recipientsOfSubclassesAction[messageType];}var item = new WeakActionAndToken{ Recipient = recipient, ThreadOption = threadOption, Action = action };list.Add(item);}}public void Unsubscribe<TMessage>(object? recipient, Action<TMessage>? action) where TMessage : Message{var messageType = typeof(TMessage);if (recipient == null || this.recipientsOfSubclassesAction == null ||this.recipientsOfSubclassesAction.Count == 0 || !this.recipientsOfSubclassesAction.ContainsKey(messageType)){return;}var lstActions = this.recipientsOfSubclassesAction[messageType];for (var i = lstActions.Count - 1; i >= 0; i--){var item = lstActions[i];var pastAction = item.Action;if (pastAction != null&& recipient == pastAction.Target&& (action == null || action.Method.Name == pastAction.Method.Name)){lstActions.Remove(item);}}}public void Publish<TMessage>(object sender, TMessage message) where TMessage : Message{var messageType = typeof(TMessage);if (this.recipientsOfSubclassesAction != null){var listClone = this.recipientsOfSubclassesAction.Keys.Take(this.recipientsOfSubclassesAction.Count).ToList();foreach (var type in listClone){List<WeakActionAndToken>? list = null;if (messageType == type || messageType.IsSubclassOf(type) || type.IsAssignableFrom(messageType)){list = this.recipientsOfSubclassesAction[type].Take(this.recipientsOfSubclassesAction[type].Count).ToList();}if (list is { Count: > 0 }){this.SendToList(message, list);}}}}private void SendToList<TMessage>(TMessage message, IEnumerable<WeakActionAndToken> weakActionsAndTokens)where TMessage : Message{var list = weakActionsAndTokens.ToList();var listClone = list.Take(list.Count()).ToList();foreach (var item in listClone){if (item.Action is { Target: { } }){switch (item.ThreadOption){case ThreadOption.BackgroundThread:Task.Run(() => { item.ExecuteWithObject(message); });break;case ThreadOption.UiThread:SynchronizationContext.Current!.Post(_ => { item.ExecuteWithObject(message); }, null);break;default:item.ExecuteWithObject(message);break;}}}}}public class WeakActionAndToken{public object? Recipient { get; set; }public ThreadOption ThreadOption { get; set; }public Delegate? Action { get; set; }public string? Tag { get; set; }public void ExecuteWithObject<TMessage>(TMessage message) where TMessage : Message{if (this.Action is Action<TMessage> factAction){factAction.Invoke(message);}}}有兴趣的看上面的代码 , 封装代码上面简单全部给上,后面的消息通知都是基于上面的三个类实现的,比较核心 。
5.2 代码整理第 5 节涉及到多窗体及多Razor组件了,需要创建一些目录存放这些文件,方便分类管理 。
【炫丽】从0开始做一个WPF+Blazor对话小程序

文章插图
  1. A:放Message,即一些消息通知类;
  2. B:放Razor组件,如果需要与Maui\Blazor Server(Wasm)等共享Razor组件,可以创建Razor类库存储;
  3. C:放通用服务,这里只放了一个窗体管理静态类,实际情况可以放Redis服务、RabbitMQ消息服务等;
  4. D:放WPF视图 , 本示例WPF窗体只是一个壳,承载BlazorWebView使用;

    推荐阅读