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> m_RecipientsOfSubclassesAction; private Dictionary> m_RecipientsStrictAction; /// /// 单例. /// 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(object recipient, Action action) { Register(recipient, null, false, action); } public virtual void Register(object recipient, bool receiveDerivedMessagesToo, Action action) { Register(recipient, null, receiveDerivedMessagesToo, action); } public virtual void Register(object recipient, object token, Action action) { Register(recipient, token, false, action); } public virtual void Register(object recipient, object token, bool receiveDerivedMessagesToo, Action action) { lock (m_RegisterLock) { var messageType = typeof(TMessage); Dictionary> recipients; if (receiveDerivedMessagesToo) { if (m_RecipientsOfSubclassesAction == null) { m_RecipientsOfSubclassesAction = new Dictionary>(); } recipients = m_RecipientsOfSubclassesAction; } else { if (m_RecipientsStrictAction == null) { m_RecipientsStrictAction = new Dictionary>(); } recipients = m_RecipientsStrictAction; } lock (recipients) { List list; if (!recipients.ContainsKey(messageType)) { list = new List(); recipients.Add(messageType, list); } else { list = recipients[messageType]; } var weakAction = new WeakAction(recipient, action); var item = new WeakActionAndToken { Action = weakAction, Token = token }; list.Add(item); } } RequestCleanup(); } private bool _isCleanupRegistered; public virtual void Send(TMessage message) { SendToTargetOrType(message, null, null); } public virtual void Send(TMessage message) { SendToTargetOrType(message, typeof(TTarget), null); } public virtual void Send(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(object recipient) { Unregister(recipient, null, null); } public virtual void Unregister(object recipient, object token) { Unregister(recipient, token, null); } public virtual void Unregister(object recipient, Action action) { Unregister(recipient, null, action); } public virtual void Unregister(object recipient, object token, Action 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> lists) { if (lists == null) { return; } lock (lists) { var listsToRemove = new List(); 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 message, IEnumerable 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> 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> 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(object recipient, object token, Action action, Dictionary> 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) { var weakActionCasted = item.Action as WeakAction; if (recipient == weakActionCasted.Target && (action == null || action.Method.Name == weakActionCasted.MethodName) && (token == null || token.Equals(item.Token))) { item.Action.MarkForDeletion(); } } } } } private void SendToTargetOrType(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 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 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; } } }