【www.bbyears.com--Windows Phone】
在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
{
Action
Func
public DelegateCommand(Action
{
m_excuteAction = excuteAction;
}
public DelegateCommand(Action
{
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 如下:
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
{
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
{
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;
}
///
/// 索引器
///
/// Key
///
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 的Tap 事件触发的时候 调用 ClickUserCommand 事件 这个Command 没有参数传入。
注意 i是:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
工程需要引用 Microsoft.Expression.Interactions
如果需要传入参数 那么代码如下:
代码如下
注意这里的Command: 的定义是
xmlns:Command="clr-namespace:WeiFan.Utility.Command;assembly=WeiFan.Utility" 该namespace是DelegateCommand 、CommandArg 和 ComandArgs 的定义所在位置
这里我们想ClickUserCommand 中 CommandArgs 集合对象 集合中有两个CommanArg元素 key 分别为1 和2 .