【UWP】使用Action代替Command

在Xaml中,说到绑定,我们用的最多的应该就是ICommand了,通过Command实现ViewModel到View之间的命令处理,例如Button默认就提供了Command支持,如下

Xaml:

    <Button Content="TestWithCommand" Command="{Binding TestCommand}" />

ViewModel

    /// <summary>Provides a base implementation of the <see cref="ICommand"/> interface. </summary>
    public abstract class CommandBase : ICommand
    {
        /// <summary>Gets a value indicating whether the command can execute in its current state. </summary>
        public abstract bool CanExecute { get; }

        /// <summary>Defines the method to be called when the command is invoked. </summary>
        protected abstract void Execute();

        /// <summary>Tries to execute the command by checking the <see cref="CanExecute"/> property
        /// and executes the command only when it can be executed. </summary>
        /// <returns>True if command has been executed; false otherwise. </returns>
        public bool TryExecute()
        {
            if (!CanExecute)
                return false;
            Execute();
            return true;
        }

        /// <summary>Occurs when changes occur that affect whether or not the command should execute. </summary>
        public event EventHandler CanExecuteChanged;

        void ICommand.Execute(object parameter)
        {
            Execute();
        }

        bool ICommand.CanExecute(object parameter)
        {
            return CanExecute;
        }
    }

    /// <summary>Provides an implementation of the <see cref="ICommand"/> interface. </summary>
    public class RelayCommand : CommandBase
    {
        private readonly Action _execute;
        private readonly Func<bool> _canExecute;

        /// <summary>Initializes a new instance of the <see cref="RelayCommand"/> class. </summary>
        /// <param name="execute">The action to execute. </param>
        public RelayCommand(Action execute)
            : this(execute, null)
        { }

        /// <summary>Initializes a new instance of the <see cref="RelayCommand"/> class. </summary>
        /// <param name="execute">The action to execute. </param>
        /// <param name="canExecute">The predicate to check whether the function can be executed. </param>
        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException(nameof(execute));

            _execute = execute;
            _canExecute = canExecute;
        }

        /// <summary>Defines the method to be called when the command is invoked. </summary>
        protected override void Execute()
        {
            _execute();
        }

        /// <summary>Gets a value indicating whether the command can execute in its current state. </summary>
        public override bool CanExecute => _canExecute == null || _canExecute();
    }

RelayCommand

    public class MainPageViewModel
    {
        public ICommand TestCommand { get; private set; }
        public MainPageViewModel()
        {
            TestCommand = new RelayCommand(TestCmd);
        }

        public void TestCmd()
        {
            Debug.WriteLine("TestCmd");
        }
    }

上面只是一个最简单的例子,但是如果需要绑定的方法很多的时候,就会有一大堆的ICommand属性定义,并且也需要初始化,代码看起来特别臃肿

下面我们使用Behavior代替Command完成方法的绑定

在WinRT中,Behavior是以组件的方法安装到VS上的,而在UWP上,官方并没有提供对应的组件,我们可以通过Nuget添加UWP版本的Behavior组件:

  http://www.nuget.org/packages/Microsoft.Xaml.Behaviors.Uwp.Managed/

使用如下

Xaml

    <Button Content="TestWithAction">
        <interactivity:Interaction.Behaviors>
            <core:EventTriggerBehavior EventName="Click">
                <core:CallMethodAction TargetObject="{Binding}" MethodName="Test"/>
            </core:EventTriggerBehavior>
        </interactivity:Interaction.Behaviors>
    </Button>

ViewModel

    public class MainPageViewModel
    {
        public void Test()
        {
            Debug.WriteLine("test");
        }
    }

  官方提供的Behavior更加灵活,可以自己配置事件名,和对应的方法名称,并且我们在ViewModel中不需要写ICommand等代码了,看起来更简洁明了,但是还有个问题,

有时候我们需要用到事件的参数,有时候我们需要用到触发事件的控件,有时候我们还需要控件对应的DataContext,而官方提供的库中并不提供带参数的方法,下面我们对其进行修改一下,让其支持参数传递,并且支持多参数

自定义一个支持参数Action

    public class Parameter : DependencyObject
    {
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
            "Value", typeof (object), typeof (Parameter), new PropertyMetadata(default(object)));

        public object Value
        {
            get { return (object) GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
    }

Parameter

    /// <summary>
    /// 带参数的Action
    /// </summary>
    [ContentProperty(Name = "Parameters")]
    public sealed class WdCallMethodAction : DependencyObject, IAction
    {
        public static readonly DependencyProperty MethodNameProperty = DependencyProperty.Register("MethodName",
            typeof (string), typeof (WdCallMethodAction), new PropertyMetadata(null));

        public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register("TargetObject",
            typeof (object), typeof (WdCallMethodAction), new PropertyMetadata(null));

        public static readonly DependencyProperty ParametersProperty = DependencyProperty.Register(
            "Parameters", typeof (ICollection<Parameter>), typeof (WdCallMethodAction),
            new PropertyMetadata(new List<Parameter>()));

        /// <summary>
        /// 方法名:参数有?,eventArgs,sender,dataContext
        ///     eg:Test
        ///     eg:Test(?,?)
        ///     eg:Test(sender,?,?)
        /// </summary>
        public string MethodName
        {
            get { return (string) GetValue(MethodNameProperty); }
            set { SetValue(MethodNameProperty, value); }
        }

        public ICollection<Parameter> Parameters
        {
            get { return (ICollection<Parameter>) GetValue(ParametersProperty); }
            set { SetValue(ParametersProperty, value); }
        }

        public object TargetObject
        {
            get { return GetValue(TargetObjectProperty); }
            set { SetValue(TargetObjectProperty, value); }
        }

        public object Execute(object sender, object parameter)
        {
            InvokeMethod(MethodName, sender, parameter, TargetObject, Parameters);
            return true;
        }

        public void InvokeMethod(string methodName, object sender, object eventArgs, object dataContext,
            ICollection<Parameter> parameters)
        {
            var start = methodName.IndexOf(‘(‘);
            var end = methodName.IndexOf(‘)‘);

            MethodInfo methodInfo;

            if (start >= 0 && end >= 0)
            {
                var paras = methodName.Substring(start + 1, end - start - 1)
                    .Split(new[] {‘,‘, ‘ ‘}, StringSplitOptions.RemoveEmptyEntries);

                methodName = MethodName.Substring(0, start);

                var allParameter = new List<object>();
                var enumerator = parameters.GetEnumerator();
                foreach (var para in paras)
                {
                    switch (para)
                    {
                        case "?":
                            enumerator.MoveNext();
                            allParameter.Add(enumerator.Current);
                            break;
                        case "eventArgs":
                            allParameter.Add(eventArgs);
                            break;
                        case "sender":
                            allParameter.Add(sender);
                            break;
                        case "dataContext":
                            allParameter.Add(dataContext);
                            break;
                        default:
                            throw new NotImplementedException(string.Format("没有实现该参数:{0}", para));

                    }
                }

                var paramCount = paras.Length;
                methodInfo = TargetObject.GetType().GetRuntimeMethods()
                    .FirstOrDefault(m => Equals(m.Name, methodName) && m.GetParameters().Count() == paramCount);

                methodInfo.Invoke(TargetObject, allParameter.ToArray());
            }
            else
            {
                methodInfo = TargetObject.GetType().GetRuntimeMethod(methodName, new Type[0]);
                methodInfo.Invoke(TargetObject, null);
            }

        }
    }

WdCallMethodAction

Xaml

    <Button x:Name="btn" Content="TestWithActionAndParameter">
        <interactivity:Interaction.Behaviors>
            <core:EventTriggerBehavior EventName="Click">
                <command:WdCallMethodAction TargetObject="{Binding}" MethodName="Test(eventArgs, sender, dataContext, ?,?)">
                    <command:Parameter Value="32"/>
                    <!-- 参数暂不支持绑定(下面方式为空)-->
                    <command:Parameter Value="{Binding ElementName=btn}"/>
                </command:WdCallMethodAction>
            </core:EventTriggerBehavior>
        </interactivity:Interaction.Behaviors>
    </Button>

ViewModel

    public void Test(RoutedEventArgs eventArgs, FrameworkElement sender, MainPageViewModel dataContext, Parameter param1, object param2)
    {
        Debug.WriteLine("sender:{0}", sender);
        Debug.WriteLine("eventArgs:{0}", eventArgs);        Debug.WriteLine("dataContext:{0}", dataContext);
        Debug.WriteLine("param1:{0}", param1);
        Debug.WriteLine("param2:{0}", param2);
    }

注:目前Parameter暂不支持绑定

demo

  http://files.cnblogs.com/files/bomo/CommandInvokeDemo.zip

时间: 2024-08-10 04:17:13

【UWP】使用Action代替Command的相关文章

shell下action:command not found

今天测试同事写的一个shell脚本,执行的时候报错,错误代码为"action: command not found" 检查脚本发现". /etc/init.d/functions"居然被注销了, 取消注释后,继续执行脚本: 报错消失,问题得到解决.说明:一些基础的函数脚本是放在函数文件里面,比如放在/etc/init.d/functions里,与执行的内容分相分离,看起来会更清爽,大型的程序语言都是这样开发的

struts2 CVE-2012-0392 S2-008 Strict DMI does not work correctly allows remote command execution and arbitrary file overwrite

catalog 1. Description 2. Effected Scope 3. Exploit Analysis 4. Principle Of Vulnerability 5. Patch Fix 1. Description Struts2框架存在一个DevMode模式,方便开发人员调试程序.如果启用该模式,攻击者可以构造特定代码导致OGNL表达式执行,以此对主机进行入侵Remote command execution and arbitrary file overwrite, St

第 12 章 命令模式【Command Pattern】

以下内容出自:<<24种设计模式介绍与6大设计原则>> 今天讲命令模式,这个模式从名字上看就很简单,命令嘛,老大发命令,小兵执行就是了,确实是这个意思,但是更深化了,用模式来描述真是是世界的命令情况.正在看这本书的你,我猜测分为两类:已经工作的和没有工作的,先说没有工作的,那你为啥要看这本书,为了以后工作呗,只要你参见工作,你肯定会待在项目组,那今天我们就以项目组为例子来讲述命令模式. 我是我们部门的项目经理,就是一个项目的头,在中国做项目,项目经理就是什么都要懂,什么都要管,做好

设计模式之命令模式---Command Pattern

模式的定义 命令模式是一个高内聚的模式,定义如下: Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录日志,可以提供命令的撤销和恢复功能. 模式的使用场景 只要

Command 设计模式

package Command; /**定义命令的接口,声明执行的方法**/ public interface Command { public void execute(); } package Command; /**命令接口实现对象,通常会持有接受者,并调用接受者的功能来完成命令要执行的操作**/ public class ConcreteCommand implements Command { private Receiver receive = null; private String

Android启动流程分析(八) 解析init.rc的action

############################################# 本文为极度寒冰原创,转载请注明出处 ############################################# 上一章讲述了android启动过程中,加载init.rc之后需要对其进行解析. 而解析又根据三个不同的SECTION来执行不同的初始化的文件,分别是parse_action,parse_service,parse_import. 那么,这一节,我们就从parse_action来讲

Android启动流程分析(十) action的执行和service的启动

############################################# 本文为极度寒冰原创,转载请注明出处 ############################################# 在前面的文章分析完init.rc的解析以后,我们知道现在action按照init.c的main函数中的秩序,维护了一条qlist的链表,listnode为action_qlist service也维护了一条链表,listnode为service_list. 那么,在android

Java设计模式(六) Command(命令模式)及Tomcat引申

基本概念 Command 命令模式是一个高内聚的模式(满足单一职责原则) 概念:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 命令模式在项目中频繁使用,封装性和拓展性都有很好的保障 Command模式中的角色分工: Client:创建一个命令并决定接受者 Command:命令接口,定义一个抽象方法 Concrete Command:具体命令,负责调用接受者的相关操作 Invoker:请求者,负责调用命令对象执行请求 R

Java开发中的23种设计模式详解(转)

设计模式(Design Patterns) --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样.项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周