欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WPF使用成熟的命令系统

程序员文章站 2024-02-16 10:49:58
...

需要的三个类如下所示:
WPF使用成熟的命令系统

对应的代码分别如下所示,直接Copy即可(只需要 注意一下命名空间):

RelayCommand 命令类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Notepad_WPF.Helpers
{
    public class RelayCommand : ICommand
    {
        private readonly WeakAction _execute;

        private readonly WeakFunc<bool> _canExecute;
         
        public RelayCommand(Action execute, bool keepTargetAlive = false)
            : this(execute, null, keepTargetAlive)
        {
        }
        
        public RelayCommand(Action execute, Func<bool> canExecute, bool keepTargetAlive = false)
        {
            if (execute == null)
            {
                throw new ArgumentNullException("execute");
            }

            _execute = new WeakAction(execute, keepTargetAlive);

            if (canExecute != null)
            {
                _canExecute = new WeakFunc<bool>(canExecute, keepTargetAlive);
            }
        }
         
        private EventHandler _requerySuggestedLocal;
         
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                { 
                    EventHandler handler2;
                    EventHandler canExecuteChanged = _requerySuggestedLocal;

                    do
                    {
                        handler2 = canExecuteChanged;
                        EventHandler handler3 = (EventHandler)Delegate.Combine(handler2, value);
                        canExecuteChanged = System.Threading.Interlocked.CompareExchange<EventHandler>(
                            ref _requerySuggestedLocal,
                            handler3,
                            handler2);
                    }
                    while (canExecuteChanged != handler2);

                    CommandManager.RequerySuggested += value;
                }
            }

            remove
            {
                if (_canExecute != null)
                { 
                    EventHandler handler2;
                    EventHandler canExecuteChanged = this._requerySuggestedLocal;

                    do
                    {
                        handler2 = canExecuteChanged;
                        EventHandler handler3 = (EventHandler)Delegate.Remove(handler2, value);
                        canExecuteChanged = System.Threading.Interlocked.CompareExchange<EventHandler>(
                            ref this._requerySuggestedLocal,
                            handler3,
                            handler2);
                    }
                    while (canExecuteChanged != handler2);

                    CommandManager.RequerySuggested -= value;
                }
            }
        } 

        public void RaiseCanExecuteChanged()
        { 
            CommandManager.InvalidateRequerySuggested(); 
        }
         
        public bool CanExecute(object parameter)
        {
            return _canExecute == null
                || (_canExecute.IsStatic || _canExecute.IsAlive)
                    && _canExecute.Execute();
        }
         
        public virtual void Execute(object parameter)
        {
            if (CanExecute(parameter)
                && _execute != null
                && (_execute.IsStatic || _execute.IsAlive))
            {
                _execute.Execute();
            }
        }
    }
}

WeakAction 辅助类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Notepad_WPF.Helpers
{
    public class WeakAction
    { 
        private Action _staticAction;
         
        protected MethodInfo Method
        {
            get;
            set;
        }
         
        public virtual string MethodName
        {
            get
            {
                if (_staticAction != null)
                { 
                    return _staticAction.Method.Name;
                }
                 
                return Method.Name; 
            }
        }
         
        protected WeakReference ActionReference
        {
            get;
            set;
        } 

        protected object LiveReference
        {
            get;
            set;
        }
         
        protected WeakReference Reference
        {
            get;
            set;
        }
         
        public bool IsStatic
        {
            get
            { 
                return _staticAction != null; 
            }
        }
         
        protected WeakAction()
        {
        }
         
        public WeakAction(Action action, bool keepTargetAlive = false)
            : this(action == null ? null : action.Target, action, keepTargetAlive)
        {
        }
         
        public WeakAction(object target, Action action, bool keepTargetAlive = false)
        { 
            if (action.Method.IsStatic) 
            {
                _staticAction = action;

                if (target != null)
                { 
                    Reference = new WeakReference(target);
                }

                return;
            } 
            Method = action.Method; 
            ActionReference = new WeakReference(action.Target); 

            LiveReference = keepTargetAlive ? action.Target : null;
            Reference = new WeakReference(target);
             
            if (ActionReference != null
                && ActionReference.Target != null
                && !keepTargetAlive)
            {
                var type = ActionReference.Target.GetType();

                if (type.Name.StartsWith("<>")
                    && type.Name.Contains("DisplayClass"))
                {
                    System.Diagnostics.Debug.WriteLine(
                        "You are attempting to register a lambda with a closure without using keepTargetAlive. Are you sure? Check http://galasoft.ch/s/mvvmweakaction for more info.");
                }
            } 
        }
         
        public virtual bool IsAlive
        {
            get
            {
                if (_staticAction == null
                    && Reference == null
                    && LiveReference == null)
                {
                    return false;
                }

                if (_staticAction != null)
                {
                    if (Reference != null)
                    {
                        return Reference.IsAlive;
                    }

                    return true;
                }
                 
                if (LiveReference != null)
                {
                    return true;
                }

                if (Reference != null)
                {
                    return Reference.IsAlive;
                }

                return false;
            }
        }
         
        public object Target
        {
            get
            {
                if (Reference == null)
                {
                    return null;
                }

                return Reference.Target;
            }
        }
         
        protected object ActionTarget
        {
            get
            {
                if (LiveReference != null)
                {
                    return LiveReference;
                }

                if (ActionReference == null)
                {
                    return null;
                }

                return ActionReference.Target;
            }
        }
         
        public void Execute()
        {
            if (_staticAction != null)
            {
                _staticAction();
                return;
            }

            var actionTarget = ActionTarget;

            if (IsAlive)
            {
                if (Method != null
                    && (LiveReference != null
                        || ActionReference != null)
                    && actionTarget != null)
                {
                    Method.Invoke(actionTarget, null);
                     
                    return; 
                }
            }
        }
         
        public void MarkForDeletion()
        {
            Reference = null;
            ActionReference = null;
            LiveReference = null;
            Method = null;
            _staticAction = null;
             
        }
    }
}

WeakFunc 辅助类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Notepad_WPF.Helpers
{
    public class WeakFunc<TResult>
    { 
        private Func<TResult> _staticFunc;
         
        protected MethodInfo Method
        {
            get;
            set;
        }
         
        public bool IsStatic
        {
            get
            { 
                return _staticFunc != null; 
            }
        }
         
        public virtual string MethodName
        {
            get
            {
                if (_staticFunc != null)
                {  
                    return _staticFunc.Method.Name; 
                }
                 
                return Method.Name; 
            }
        }
         
        protected WeakReference FuncReference
        {
            get;
            set;
        }
         
        protected object LiveReference
        {
            get;
            set;
        }
         
        protected WeakReference Reference
        {
            get;
            set;
        }
         
        protected WeakFunc()
        {
        }
         
        public WeakFunc(Func<TResult> func, bool keepTargetAlive = false)
            : this(func == null ? null : func.Target, func, keepTargetAlive)
        {
        }
         
        public WeakFunc(object target, Func<TResult> func, bool keepTargetAlive = false)
        {  
            if (func.Method.IsStatic) 
            {
                _staticFunc = func;

                if (target != null)
                { 
                    Reference = new WeakReference(target);
                }

                return;
            }
             
            Method = func.Method; 
            FuncReference = new WeakReference(func.Target); 

            LiveReference = keepTargetAlive ? func.Target : null;
            Reference = new WeakReference(target);
             
            if (FuncReference != null
                && FuncReference.Target != null
                && !keepTargetAlive)
            {
                var type = FuncReference.Target.GetType();

                if (type.Name.StartsWith("<>")
                    && type.Name.Contains("DisplayClass"))
                {
                    System.Diagnostics.Debug.WriteLine(
                        "You are attempting to register a lambda with a closure without using keepTargetAlive. Are you sure? Check http://galasoft.ch/s/mvvmweakaction for more info.");
                }
            } 
        }
         
        public virtual bool IsAlive
        {
            get
            {
                if (_staticFunc == null
                    && Reference == null
                    && LiveReference == null)
                {
                    return false;
                }

                if (_staticFunc != null)
                {
                    if (Reference != null)
                    {
                        return Reference.IsAlive;
                    }

                    return true;
                }

                // Non static action

                if (LiveReference != null)
                {
                    return true;
                }

                if (Reference != null)
                {
                    return Reference.IsAlive;
                }

                return false;
            }
        }
         
        public object Target
        {
            get
            {
                if (Reference == null)
                {
                    return null;
                }

                return Reference.Target;
            }
        }
         
        protected object FuncTarget
        {
            get
            {
                if (LiveReference != null)
                {
                    return LiveReference;
                }

                if (FuncReference == null)
                {
                    return null;
                }

                return FuncReference.Target;
            }
        }
          
        public TResult Execute()
        {
            if (_staticFunc != null)
            {
                return _staticFunc();
            }

            var funcTarget = FuncTarget;

            if (IsAlive)
            {
                if (Method != null
                    && (LiveReference != null
                        || FuncReference != null)
                    && funcTarget != null)
                {
                    return (TResult)Method.Invoke(funcTarget, null);
                }
                 
            }

            return default(TResult);
        }
         
        public void MarkForDeletion()
        {
            Reference = null;
            FuncReference = null;
            LiveReference = null;
            Method = null;
            _staticFunc = null; 
        }
    }
}


使用方式非常的简单方便,如下所示:
WPF使用成熟的命令系统
其中的 RelayCommand对象中有多种重载版本 . . .