Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF MVVM与Messenger的通信(VM的邮件加载)_C#_Wpf_Mvvm_Communication_Messenger - Fatal编程技术网

C# WPF MVVM与Messenger的通信(VM的邮件加载)

C# WPF MVVM与Messenger的通信(VM的邮件加载),c#,wpf,mvvm,communication,messenger,C#,Wpf,Mvvm,Communication,Messenger,背景 我正在使用MVVM模式编写WPF应用程序。我正在使用Messenger在ViewModels之间进行通信,这是我在各种教程中学习到的。我正在使用本文代码部分中的Messenger类的实现(感谢Pluralsight上的@Dalstroem和Gill Cleeren) 由于我的应用程序需要大量的视图/虚拟机,因此在需要视图时会实例化每个视图模型,并随后进行处理(视图优先,虚拟机指定为视图的DataContext) 问题 public class Messenger { private

背景

我正在使用MVVM模式编写WPF应用程序。我正在使用Messenger在ViewModels之间进行通信,这是我在各种教程中学习到的。我正在使用本文代码部分中的Messenger类的实现(感谢Pluralsight上的@Dalstroem和Gill Cleeren)

由于我的应用程序需要大量的视图/虚拟机,因此在需要视图时会实例化每个视图模型,并随后进行处理(视图优先,虚拟机指定为视图的DataContext)

问题

public class Messenger
{
    private static readonly object CreationLock = new object();
    private static readonly ConcurrentDictionary<MessengerKey, object> Dictionary = new ConcurrentDictionary<MessengerKey, object>();

    #region Default property

    private static Messenger _instance;

    /// <summary>
    /// Gets the single instance of the Messenger.
    /// </summary>
    public static Messenger Default
    {
        get
        {
            if (_instance == null)
            {
                lock (CreationLock)
                {
                    if (_instance == null)
                    {
                        _instance = new Messenger();
                    }
                }
            }

            return _instance;
        }
    }

    #endregion

    /// <summary>
    /// Initializes a new instance of the Messenger class.
    /// </summary>
    private Messenger()
    {
    }

    /// <summary>
    /// Registers a recipient for a type of message T. The action parameter will be executed
    /// when a corresponding message is sent.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="recipient"></param>
    /// <param name="action"></param>
    public void Register<T>(object recipient, Action<T> action)
    {
        Register(recipient, action, null);
    }

    /// <summary>
    /// Registers a recipient for a type of message T and a matching context. The action parameter will be executed
    /// when a corresponding message is sent.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="recipient"></param>
    /// <param name="action"></param>
    /// <param name="context"></param>
    public void Register<T>(object recipient, Action<T> action, object context)
    {
        var key = new MessengerKey(recipient, context);
        Dictionary.TryAdd(key, action);
    }

    /// <summary>
    /// Unregisters a messenger recipient completely. After this method is executed, the recipient will
    /// no longer receive any messages.
    /// </summary>
    /// <param name="recipient"></param>
    public void Unregister(object recipient)
    {
        Unregister(recipient, null);
    }

    /// <summary>
    /// Unregisters a messenger recipient with a matching context completely. After this method is executed, the recipient will
    /// no longer receive any messages.
    /// </summary>
    /// <param name="recipient"></param>
    /// <param name="context"></param>
    public void Unregister(object recipient, object context)
    {
        object action;
        var key = new MessengerKey(recipient, context);
        Dictionary.TryRemove(key, out action);
    }

    /// <summary>
    /// Sends a message to registered recipients. The message will reach all recipients that are
    /// registered for this message type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="message"></param>
    public void Send<T>(T message)
    {
        Send(message, null);
    }

    /// <summary>
    /// Sends a message to registered recipients. The message will reach all recipients that are
    /// registered for this message type and matching context.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="message"></param>
    /// <param name="context"></param>
    public void Send<T>(T message, object context)
    {
        IEnumerable<KeyValuePair<MessengerKey, object>> result;

        if (context == null)
        {
            // Get all recipients where the context is null.
            result = from r in Dictionary where r.Key.Context == null select r;
        }
        else
        {
            // Get all recipients where the context is matching.
            result = from r in Dictionary where r.Key.Context != null && r.Key.Context.Equals(context) select r;
        }

        foreach (var action in result.Select(x => x.Value).OfType<Action<T>>())
        {
            // Send the message to all recipients.
            action(message);
        }
    }

    protected class MessengerKey
    {
        public object Recipient { get; private set; }
        public object Context { get; private set; }

        /// <summary>
        /// Initializes a new instance of the MessengerKey class.
        /// </summary>
        /// <param name="recipient"></param>
        /// <param name="context"></param>
        public MessengerKey(object recipient, object context)
        {
            Recipient = recipient;
            Context = context;
        }

        /// <summary>
        /// Determines whether the specified MessengerKey is equal to the current MessengerKey.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        protected bool Equals(MessengerKey other)
        {
            return Equals(Recipient, other.Recipient) && Equals(Context, other.Context);
        }

        /// <summary>
        /// Determines whether the specified MessengerKey is equal to the current MessengerKey.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;

            return Equals((MessengerKey)obj);
        }

        /// <summary>
        /// Serves as a hash function for a particular type. 
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            unchecked
            {
                return ((Recipient != null ? Recipient.GetHashCode() : 0) * 397) ^ (Context != null ? Context.GetHashCode() : 0);
            }
        }
    }
}
每个ViewModel的构造函数根据需要加载资源(命令、服务等),并注册感兴趣的消息。从以前存在的ViewModels发送的消息不会被新的ViewModels拾取

因此,我无法使用Messenger类在ViewModels之间进行通信

思想

我看到的一些示例使用ViewModelLocator预先实例化所有ViewModel。创建视图时,只需从VML中提取现有的ViewModel。这种方法意味着消息将始终在每个ViewModel中接收并可用。我担心的是,30多个ViewModels在使用时都会加载大量数据,随着每个视图的使用,我的应用程序在扩展使用时会变得很慢(从来没有配置过资源)

我考虑过找到一种存储邮件的方法,然后将所有邮件重新发送给任何已注册的收件人。如果实现,这将允许我在每个ViewModel中注册消息后调用重发排序方法。我对这种方法有一些担忧,包括随着时间的推移信息的积累

我不确定我做错了什么,也不确定是否有我不知道的方法

代码

public class Messenger
{
    private static readonly object CreationLock = new object();
    private static readonly ConcurrentDictionary<MessengerKey, object> Dictionary = new ConcurrentDictionary<MessengerKey, object>();

    #region Default property

    private static Messenger _instance;

    /// <summary>
    /// Gets the single instance of the Messenger.
    /// </summary>
    public static Messenger Default
    {
        get
        {
            if (_instance == null)
            {
                lock (CreationLock)
                {
                    if (_instance == null)
                    {
                        _instance = new Messenger();
                    }
                }
            }

            return _instance;
        }
    }

    #endregion

    /// <summary>
    /// Initializes a new instance of the Messenger class.
    /// </summary>
    private Messenger()
    {
    }

    /// <summary>
    /// Registers a recipient for a type of message T. The action parameter will be executed
    /// when a corresponding message is sent.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="recipient"></param>
    /// <param name="action"></param>
    public void Register<T>(object recipient, Action<T> action)
    {
        Register(recipient, action, null);
    }

    /// <summary>
    /// Registers a recipient for a type of message T and a matching context. The action parameter will be executed
    /// when a corresponding message is sent.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="recipient"></param>
    /// <param name="action"></param>
    /// <param name="context"></param>
    public void Register<T>(object recipient, Action<T> action, object context)
    {
        var key = new MessengerKey(recipient, context);
        Dictionary.TryAdd(key, action);
    }

    /// <summary>
    /// Unregisters a messenger recipient completely. After this method is executed, the recipient will
    /// no longer receive any messages.
    /// </summary>
    /// <param name="recipient"></param>
    public void Unregister(object recipient)
    {
        Unregister(recipient, null);
    }

    /// <summary>
    /// Unregisters a messenger recipient with a matching context completely. After this method is executed, the recipient will
    /// no longer receive any messages.
    /// </summary>
    /// <param name="recipient"></param>
    /// <param name="context"></param>
    public void Unregister(object recipient, object context)
    {
        object action;
        var key = new MessengerKey(recipient, context);
        Dictionary.TryRemove(key, out action);
    }

    /// <summary>
    /// Sends a message to registered recipients. The message will reach all recipients that are
    /// registered for this message type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="message"></param>
    public void Send<T>(T message)
    {
        Send(message, null);
    }

    /// <summary>
    /// Sends a message to registered recipients. The message will reach all recipients that are
    /// registered for this message type and matching context.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="message"></param>
    /// <param name="context"></param>
    public void Send<T>(T message, object context)
    {
        IEnumerable<KeyValuePair<MessengerKey, object>> result;

        if (context == null)
        {
            // Get all recipients where the context is null.
            result = from r in Dictionary where r.Key.Context == null select r;
        }
        else
        {
            // Get all recipients where the context is matching.
            result = from r in Dictionary where r.Key.Context != null && r.Key.Context.Equals(context) select r;
        }

        foreach (var action in result.Select(x => x.Value).OfType<Action<T>>())
        {
            // Send the message to all recipients.
            action(message);
        }
    }

    protected class MessengerKey
    {
        public object Recipient { get; private set; }
        public object Context { get; private set; }

        /// <summary>
        /// Initializes a new instance of the MessengerKey class.
        /// </summary>
        /// <param name="recipient"></param>
        /// <param name="context"></param>
        public MessengerKey(object recipient, object context)
        {
            Recipient = recipient;
            Context = context;
        }

        /// <summary>
        /// Determines whether the specified MessengerKey is equal to the current MessengerKey.
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        protected bool Equals(MessengerKey other)
        {
            return Equals(Recipient, other.Recipient) && Equals(Context, other.Context);
        }

        /// <summary>
        /// Determines whether the specified MessengerKey is equal to the current MessengerKey.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != GetType()) return false;

            return Equals((MessengerKey)obj);
        }

        /// <summary>
        /// Serves as a hash function for a particular type. 
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            unchecked
            {
                return ((Recipient != null ? Recipient.GetHashCode() : 0) * 397) ^ (Context != null ? Context.GetHashCode() : 0);
            }
        }
    }
}
公共类信使
{
私有静态只读对象CreationLock=新对象();
私有静态只读ConcurrentDictionary=新ConcurrentDictionary();
#区域默认属性
私有静态Messenger_实例;
/// 
///获取Messenger的单个实例。
/// 
公共静态信使默认值
{
得到
{
if(_instance==null)
{
锁定(CreationLock)
{
if(_instance==null)
{
_实例=新的Messenger();
}
}
}
返回_实例;
}
}
#端区
/// 
///初始化Messenger类的新实例。
/// 
私人信使()
{
}
/// 
///为一种类型的邮件T注册收件人。将执行操作参数
///当发送相应的消息时。
/// 
/// 
/// 
/// 
公共无效登记簿(对象收件人,操作)
{
登记簿(收件人、操作、空);
}
/// 
///为邮件类型T和匹配上下文注册收件人。将执行操作参数
///当发送相应的消息时。
/// 
/// 
/// 
/// 
/// 
公共无效寄存器(对象收件人、操作、对象上下文)
{
var key=新的信使密钥(收件人、上下文);
TryAdd(键,动作);
}
/// 
///完全注销messenger收件人。执行此方法后,收件人将
///不再接收任何消息。
/// 
/// 
公共作废注销(对象收件人)
{
取消注册(收件人,空);
}
/// 
///使用匹配的上下文完全注销messenger收件人。执行此方法后,收件人将
///不再接收任何消息。
/// 
/// 
/// 
公共作废注销(对象收件人、对象上下文)
{
客体行为;
var key=新的信使密钥(收件人、上下文);
TryRemove(key,out动作);
}
/// 
///向已注册的收件人发送邮件。该邮件将送达所有已注册的收件人
///已为此邮件类型注册。
/// 
/// 
/// 
公共无效发送(T消息)
{
发送(消息,空);
}
/// 
///向已注册的收件人发送邮件。该邮件将送达所有已注册的收件人
///已为此消息类型和匹配上下文注册。
/// 
/// 
/// 
/// 
公共void发送(T消息、对象上下文)
{
可数结果;
if(上下文==null)
{
//获取上下文为空的所有收件人。
结果=来自字典中的r,其中r.Key.Context==null选择r;
}
其他的
{
//获取上下文匹配的所有收件人。
result=来自字典中的r,其中r.Key.Context!=null&&r.Key.Context.Equals(Context)选择r;
}
foreach(result.Select(x=>x.Value).OfType()中的var操作)
{
//将邮件发送给所有收件人。
行动(信息);
}
}
受保护类信使密钥
{
公共对象收件人{get;private set;}
公共对象上下文{get;private set;}
/// 
///初始化MessengerKey类的新实例。
/// 
/// 
/// 
公用信使密钥(对象收件人、对象上下文)
{
收件人=收件人;
上下文=上下文;
}
/// 
///确定指定的Messenger密钥是否等于当前Messenger密钥。
/// 
/// 
/// 
受保护的bool等于(信使键其他)
{
返回等于(Recipient,other.Recipient)和等于(Context,other.Context);
}
/// 
///确定指定的Messenger密钥是否等于当前值