龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 移动开发 > Windows phone 开发 >

Windows Phone 开发 Command入门介绍

时间:2013-01-03 09:27来源:未知 作者:admin 点击:
分享到:
在VM中我们一些方法需要提供给view 使用。其中最简单的方法是直接暴露一个public 的方法由view(在xmal.cs) 中直接调用。如果我们想把这个方法绑定到页面(xaml) 中的事件则需要使用Command

在VM中我们一些方法需要提供给view 使用。其中最简单的方法是直接暴露一个public 的方法由view(在xmal.cs) 中直接调用。如果我们想把这个方法绑定到页面(xaml) 中的事件则需要使用Command. 当然在xmal.cs 中也可以直接使用Command。

 View 想使用Command 那么首先必须在VM 实现一个公开的Command属性。

在Windows Phone 的SDK 中 Command的实现必须继承与System.Windows.Input.ICommand接口: 在ICommand 中包含CanExecute 和Execute 方法和一个CanExecuteChanged 事件。

 

如果Command 是被绑定到页面上的事件中。那么系统在执行Command的时候将先执行 CanExecute 方法
如果方法返回true则执行Execute方法的方式来执行Command。在调用这两个方法的时候Command的参数均会被传入这两个方法。

同时我们建议是自己调用Command使用的话也建议遵循这样的方式。

 

在使用Command使用必然会增加代码量,当然也带来好处:

1、
可以直接绑定

2、
可以控制状态

 代码如下 复制代码

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace WeiFan.Utility.Command
{
    public class DelegateCommand<T> : ICommand where T : class
    {
        Action<T> m_excuteAction;
        Func<T, bool> m_canExcunteFunc;

        public DelegateCommand(Action<T> excuteAction)
        {
            m_excuteAction = excuteAction;
        }
        public DelegateCommand(Action<T> excuteAction, Func<T, bool> canExcuteAction)
        {
            m_canExcunteFunc=canExcuteAction;
            m_excuteAction = excuteAction;
        }

        private bool m_isCanExecute = true;
        public bool IsCanExecute
        {
            get { return m_isCanExecute; }
            set
            {
                if (value != m_isCanExecute)
                {
                    m_isCanExecute = value;
                    FireCanExecuteChanged();
                }

            }
        }

        private void FireCanExecuteChanged()
        {
            if (CanExecuteChanged !=null)
                CanExecuteChanged(this, new EventArgs());
        }

        #region ICommand Members

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            if (m_canExcunteFunc == null)
            {
                return IsCanExecute;
            }
            else
            {
                T args;

                args = parameter as T;


                IsCanExecute = m_canExcunteFunc(args);
            }
            return IsCanExecute;
        }

        public void Execute(object parameter)
        {
            if (m_excuteAction != null)
            {
                T args;

                args = parameter as T;

                m_excuteAction(args);
            }
        }


        #endregion
       
    }
}
 

现在我们先来Command如何实现。一般来说我在代码中实现一个基础的通用Command,已代理的方式在Command 构建的时候传入Execute 方法和CanExecute的具体逻辑。


代码如下:
其中泛型T为Command 参数类型。
那么 我们在VM 中使用该Command 如下:

 代码如下 复制代码
private DelegateCommand<string> m_clickImageCommand;
        public ICommand ClickImageCommand { get { return m_clickImageCommand; } }

注意这个Command 是调用的时候接受一个 string 类型的参数。 这个Command的CanExecute 永远返回True 也就是说无论什么时候 该Command 都可以执行。

接下来我们来聊聊Command 的参数
首先Command在使用的是有允许传入一个 Object 类型的参数。 如果我们的Command 只接收一个参数到好说 在泛型里面限定类型就OK 了。。。  如果要接受多个参数的话就很蛋疼了。。
在这里我选择采用 一个集合类型将多个参数打包成一个集合传入Command。
考虑到为了让其使用起来友好 又能方便绑定我选择该集合采用简直对的方式 集合中的每个元素包含一个key 和一个value . 元素可以使用index  来索引 可以使用key 来索引。

代码如下:
CommandArg:

 

 代码如下 复制代码

[ContentProperty("Value")]
    public class CommandArg : DependencyObject, IEquatable<CommandArg>
    {

        public CommandArg(string key, Object value)
        {
            this.Key = key;
            this.Value = value;
        }

        public CommandArg() { }

        private const string KEY_CAN_NOT_NULL = "绑定参数的key不能为空";

        #region DependencyProperty


        private static readonly DependencyProperty KeyProperty = DependencyProperty.Register("Key", typeof(string), typeof(CommandArg), new PropertyMetadata(new Random().Next().ToString(), KeyPropertyChanged));
       
        private static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(Object), typeof(CommandArg), new PropertyMetadata(null));

        private static void KeyPropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(Convert.ToString(e.NewValue)) && string.IsNullOrEmpty(Convert.ToString(e.NewValue)))
                throw new Exception(KEY_CAN_NOT_NULL);
        }

        bool m_isSetKey = false;
     
        public string Key
        {
            get { return Convert.ToString(GetValue(KeyProperty)); }
            set
            {
                if (string.IsNullOrWhiteSpace(Convert.ToString(value)))
                {
                    throw new ArgumentException(KEY_CAN_NOT_NULL);
                }
                else
                {
                    if (m_isSetKey == false)
                    {
                        SetValue(KeyProperty, value);
                        m_isSetKey = true;
                    }
                    else
                    {
                        throw new InvalidOperationException("KEY_HAS_BEEN_SET");
                    }

                }
            }
        }

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

        #endregion

        public override string ToString()
        {
            return string.Format("({0},{1})", this.Key, this.Value);
        }

       

        #region IEquatable接口实现

        public bool Equals(CommandArg other)
        {
            if (other == null) return false;
            return string.Equals(Key, other.Key, StringComparison.InvariantCultureIgnoreCase) && Value == other.Value;
        }

        #endregion
    }

这是集合中单个元素对象

CommandArgs:

 

 代码如下 复制代码

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using WeiFan.Utility.Command;

namespace WeiFan.Utility.Command
{
    public class CommandArgs: DependencyObjectCollection<CommandArg>
    {
        public CommandArgs():
            base()
        {
            base.Clear();
           
            base.CollectionChanged += new NotifyCollectionChangedEventHandler(CommandArgs_CollectionChanged);
           
        }

       

        void CommandArgs_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems!=null)
            {
                foreach (CommandArg arg in e.NewItems)
                {
                    CommandArg containArg = GetItemByKey(arg.Key);

                    if (containArg != null && !containArg.Equals(arg))
                    {
                        throw new Exception("The collection contains this key");
                    }
                }
            }
        }

        

        public new void SetValue(DependencyProperty dp, object value)
        {
            //System.Diagnostics.Debug.WriteLine("SetValue");
            base.SetValue(dp, value);
        }

        public bool Contains(string key)
        {
            if (GetItemByKey(key) == null)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
   

        public new void Add(CommandArg item)
        {
         
            if (GetItemByKey(item.Key) != null)
            {
                throw new Exception("The collection contains this key");
            }
            else
            {
                base.Add(item);
            }
        }

     
        private CommandArg GetItemByKey(string key)
        {
            if (!String.IsNullOrEmpty(key) && !String.IsNullOrWhiteSpace(key))
            {
                for (int i = 0; i < base.Count; i++)
                {
                    CommandArg arg = base[i];
                    if (arg.Key == key)
                    {
                        return arg;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 索引器
        /// </summary>
        /// <param name="key">Key</param>
        /// <returns></returns>
        public CommandArg this[string key]
        {
            get
            {
                return GetItemByKey(key);
            }
            set
            {
                CommandArg arg = GetItemByKey(key);
                if (arg == null)
                {
                    throw new NullReferenceException();
                }
                else
                {
                    arg = value;
                }
            }
        }
      
    }
}

这是参数集合

 

好了。 接下来的事情我们就来看下 VM 中的Command 如何使用了

先看简单的吧 xaml.cs 中使用:

 代码如下 复制代码
if (m_statusVM.LoadComand.CanExecute(null))
            {
                m_statusVM.LoadComand.Execute(null);
            }

这里该是什么参数就在CanExecute 和 Execute 里面传什么参数


如果想在xaml 中绑定command 的话 需要使用Trigger 将Command和控件事件绑定起来:
代码如下:

 

 代码如下 复制代码
<Image x:Name="imgMyImage" VerticalAlignment="Top"  Width="75" Height="75" Source="{Binding Path=Status.User.ProfileImageUrl}" >
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Tap">
                                <i:InvokeCommandAction Command="{Binding Path=ClickUserCommand}"></i:InvokeCommandAction>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </Image>

在这里 当Image 的Tap 事件触发的时候 调用 ClickUserCommand 事件 这个Command 没有参数传入。
注意 i是:

 代码如下 复制代码

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 

工程需要引用 Microsoft.Expression.Interactions

如果需要传入参数 那么代码如下:

 

 代码如下 复制代码

<Image x:Name="imgMyImage" VerticalAlignment="Top"  Width="75" Height="75" Source="{Binding Path=Status.User.ProfileImageUrl}" >
                       
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Tap">
                                <i:InvokeCommandAction Command="{Binding Path=ClickUserCommand}">
                                    <i:InvokeCommandAction.CommandParameter>
                                        <Command:CommandArgs>
                                            <Command:CommandArg Value="sdf" Key="1"></Command:CommandArg>
                                            <Command:CommandArg Value="sdf" Key="2"></Command:CommandArg>

                                        </Command:CommandArgs>   
                                    </i:InvokeCommandAction.CommandParameter>
                                </i:InvokeCommandAction>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </Image>

注意这里的Command: 的定义是   
xmlns:Command="clr-namespace:WeiFan.Utility.Command;assembly=WeiFan.Utility"     该namespace是DelegateCommand 、CommandArg 和 ComandArgs 的定义所在位置

这里我们想ClickUserCommand 中 CommandArgs 集合对象 集合中有两个CommanArg元素 key 分别为1 和2 .

 


精彩图集

赞助商链接