Files
DotNet.Revit/DotNet.RevitUI/MVVM/Messenger.cs

387 lines
12 KiB
C#
Raw Normal View History

2026-02-23 16:57:09 +08:00
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace DotNet.RevitUI.MVVM
{
public class Messenger : IMessenger
{
private static readonly object CreationLock = new object();
private static IMessenger m_DefaultInstance;
private readonly object m_RegisterLock = new object();
private Dictionary<Type, List<WeakActionAndToken>> m_RecipientsOfSubclassesAction;
private Dictionary<Type, List<WeakActionAndToken>> m_RecipientsStrictAction;
/// <summary>
/// 单例.
/// </summary>
public static IMessenger Default
{
get
{
if (m_DefaultInstance == null)
{
lock (CreationLock)
{
if (m_DefaultInstance == null)
{
m_DefaultInstance = new Messenger();
}
}
}
return m_DefaultInstance;
}
}
public virtual void Register<TMessage>(object recipient, Action<TMessage> action)
{
Register(recipient, null, false, action);
}
public virtual void Register<TMessage>(object recipient, bool receiveDerivedMessagesToo, Action<TMessage> action)
{
Register(recipient, null, receiveDerivedMessagesToo, action);
}
public virtual void Register<TMessage>(object recipient, object token, Action<TMessage> action)
{
Register(recipient, token, false, action);
}
public virtual void Register<TMessage>(object recipient, object token, bool receiveDerivedMessagesToo, Action<TMessage> action)
{
lock (m_RegisterLock)
{
var messageType = typeof(TMessage);
Dictionary<Type, List<WeakActionAndToken>> recipients;
if (receiveDerivedMessagesToo)
{
if (m_RecipientsOfSubclassesAction == null)
{
m_RecipientsOfSubclassesAction = new Dictionary<Type, List<WeakActionAndToken>>();
}
recipients = m_RecipientsOfSubclassesAction;
}
else
{
if (m_RecipientsStrictAction == null)
{
m_RecipientsStrictAction = new Dictionary<Type, List<WeakActionAndToken>>();
}
recipients = m_RecipientsStrictAction;
}
lock (recipients)
{
List<WeakActionAndToken> list;
if (!recipients.ContainsKey(messageType))
{
list = new List<WeakActionAndToken>();
recipients.Add(messageType, list);
}
else
{
list = recipients[messageType];
}
var weakAction = new WeakAction<TMessage>(recipient, action);
var item = new WeakActionAndToken
{
Action = weakAction,
Token = token
};
list.Add(item);
}
}
RequestCleanup();
}
private bool _isCleanupRegistered;
public virtual void Send<TMessage>(TMessage message)
{
SendToTargetOrType(message, null, null);
}
public virtual void Send<TMessage, TTarget>(TMessage message)
{
SendToTargetOrType(message, typeof(TTarget), null);
}
public virtual void Send<TMessage>(TMessage message, object token)
{
SendToTargetOrType(message, null, token);
}
public virtual void Unregister(object recipient)
{
UnregisterFromListsByRecipient(recipient, m_RecipientsOfSubclassesAction);
UnregisterFromListsByRecipient(recipient, m_RecipientsStrictAction);
}
public void Unregister(string token)
{
UnregisterFromListsByToken(token, m_RecipientsOfSubclassesAction);
UnregisterFromListsByToken(token, m_RecipientsStrictAction);
}
public virtual void Unregister<TMessage>(object recipient)
{
Unregister<TMessage>(recipient, null, null);
}
public virtual void Unregister<TMessage>(object recipient, object token)
{
Unregister<TMessage>(recipient, token, null);
}
public virtual void Unregister<TMessage>(object recipient, Action<TMessage> action)
{
Unregister(recipient, null, action);
}
public virtual void Unregister<TMessage>(object recipient, object token, Action<TMessage> action)
{
UnregisterFromLists(recipient, token, action, m_RecipientsStrictAction);
UnregisterFromLists(recipient, token, action, m_RecipientsOfSubclassesAction);
RequestCleanup();
}
public static void OverrideDefault(IMessenger newMessenger)
{
m_DefaultInstance = newMessenger;
}
public static void Reset()
{
m_DefaultInstance = null;
}
public void ResetAll()
{
Reset();
}
public void RequestCleanup()
{
if (!_isCleanupRegistered)
{
Action cleanupAction = Cleanup;
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(cleanupAction, System.Windows.Threading.DispatcherPriority.ApplicationIdle, null);
_isCleanupRegistered = true;
}
}
public void Cleanup()
{
CleanupList(m_RecipientsOfSubclassesAction);
CleanupList(m_RecipientsStrictAction);
_isCleanupRegistered = false;
}
private static void CleanupList(IDictionary<Type, List<WeakActionAndToken>> lists)
{
if (lists == null)
{
return;
}
lock (lists)
{
var listsToRemove = new List<Type>();
foreach (var list in lists)
{
var recipientsToRemove = list.Value
.Where(item => item.Action == null || !item.Action.IsAlive)
.ToList();
foreach (var recipient in recipientsToRemove)
{
list.Value.Remove(recipient);
}
if (list.Value.Count == 0)
{
listsToRemove.Add(list.Key);
}
}
foreach (var key in listsToRemove)
{
lists.Remove(key);
}
}
}
private static void SendToList<TMessage>(TMessage message, IEnumerable<WeakActionAndToken> weakActionsAndTokens, Type messageTargetType, object token)
{
if (weakActionsAndTokens != null)
{
// Correction Messaging BL0004.007
var list = weakActionsAndTokens.ToList();
var listClone = list.Take(list.Count()).ToList();
foreach (var item in listClone)
{
var executeAction = item.Action as IExecuteWithObject;
if (executeAction != null
&& item.Action.IsAlive
&& item.Action.Target != null
&& (messageTargetType == null
|| item.Action.Target.GetType() == messageTargetType
|| messageTargetType.IsAssignableFrom(item.Action.Target.GetType()))
&& ((item.Token == null && token == null)
|| item.Token != null && item.Token.Equals(token)))
{
executeAction.ExecuteWithObject(message);
}
}
}
}
private static void UnregisterFromListsByToken(object token, Dictionary<Type, List<WeakActionAndToken>> lists)
{
if (token == null || lists == null || lists.Count == 0)
{
return;
}
lock (lists)
{
foreach (var messageType in lists.Keys)
{
foreach (var item in lists[messageType])
{
if (item.Action != null && item.Token == token)
{
item.Action.MarkForDeletion();
}
}
}
}
}
private static void UnregisterFromListsByRecipient(object recipient, Dictionary<Type, List<WeakActionAndToken>> lists)
{
if (recipient == null || lists == null || lists.Count == 0)
{
return;
}
lock (lists)
{
foreach (var messageType in lists.Keys)
{
foreach (var item in lists[messageType])
{
var weakAction = (IExecuteWithObject)item.Action;
if (weakAction != null
&& recipient == weakAction.Target)
{
weakAction.MarkForDeletion();
}
}
}
}
}
private static void UnregisterFromLists<TMessage>(object recipient, object token, Action<TMessage> action, Dictionary<Type, List<WeakActionAndToken>> lists)
{
var messageType = typeof(TMessage);
if (recipient == null || lists == null || lists.Count == 0 || !lists.ContainsKey(messageType))
{
return;
}
lock (lists)
{
foreach (var item in lists[messageType])
{
if (item.Action is WeakAction<TMessage>)
{
var weakActionCasted = item.Action as WeakAction<TMessage>;
if (recipient == weakActionCasted.Target
&& (action == null || action.Method.Name == weakActionCasted.MethodName)
&& (token == null || token.Equals(item.Token)))
{
item.Action.MarkForDeletion();
}
}
}
}
}
private void SendToTargetOrType<TMessage>(TMessage message, Type messageTargetType, object token)
{
var messageType = typeof(TMessage);
if (m_RecipientsOfSubclassesAction != null)
{
var listClone = m_RecipientsOfSubclassesAction.Keys.Take(m_RecipientsOfSubclassesAction.Count()).ToList();
foreach (var type in listClone)
{
List<WeakActionAndToken> list = null;
if (messageType == type || messageType.IsSubclassOf(type) || type.IsAssignableFrom(messageType))
{
lock (m_RecipientsOfSubclassesAction)
{
list = m_RecipientsOfSubclassesAction[type].Take(m_RecipientsOfSubclassesAction[type].Count()).ToList();
}
}
SendToList(message, list, messageTargetType, token);
}
}
if (m_RecipientsStrictAction != null)
{
List<WeakActionAndToken> list = null;
lock (m_RecipientsStrictAction)
{
if (m_RecipientsStrictAction.ContainsKey(messageType))
{
list = m_RecipientsStrictAction[messageType]
.Take(m_RecipientsStrictAction[messageType].Count())
.ToList();
}
}
if (list != null)
{
SendToList(message, list, messageTargetType, token);
}
}
RequestCleanup();
}
private struct WeakActionAndToken
{
public WeakAction Action;
public object Token;
}
}
}