在这里我打算分享一个十分轻量级的技巧实现Silverlight4中的Command。
Step 1 – 实现ICommand接口
第一步是新建一个类来管理Command相关的逻辑,它需要实现ICommand接口。当然,还有很多其他的方式,我在这里只介绍这种简单有效的实现。
DelegatedCommand类实现了ICommand接口定义的CanExecute、Execute方法和CanExecuteChanged事件。
public class DelegateCommand : ICommand { Func<object, bool> canExecute; Action<object> executeAction; bool canExecuteCache; public DelegateCommand(Action<object> executeAction, Func<object, bool> canExecute) { this.executeAction = executeAction; this.canExecute = canExecute; } #region ICommand 成员 public bool CanExecute(object parameter) { bool temp = canExecute(parameter); if (canExecuteCache != temp) { canExecuteCache = temp; if (CanExecuteChanged != null) { CanExecuteChanged(this, new EventArgs()); } } return canExecuteCache; } public event EventHandler CanExecuteChanged; public void Execute(object parameter) { executeAction(parameter); } #endregion }
Step 2 – 定义Command
在你的ViewModel中增加一个公共属性对外提供ICommand。一般来说,这个属性会绑定到界面的按钮上。
public ICommand LoadProductsCommand { get; set; }
Step 3 – 创建Command
在你的ViewModel的构造函数中通过第一步中创建的DelegateCommand类实例化LoadProductsCommand。
LoadProductsCommand = new DelegateCommand(LoadProducts, CanLoadProducts);
Step 4 – 创建ViewModel
接下来你需要确认你的View可以和你的ViewModel通信。很多方式都可以实现这一点,这里我是将ViewModel在XAML中定义为一个静态资源。
<UserControl.Resources> <local:ProductViewModel x:Key="vm"/> </UserControl.Resources>
Step 5 – 绑定到Command
向UI中添加一个按钮然后将你ViewModel中创建的Command属性绑定到这个按钮上。接下来你可能需要通过设置绑定中的CommandParameter向Command传递参数,这里可以是一个UI元素,如TextBox。
<Button Content="Load" Width="120" Command="{Binding LoadProductsCommand}" CommandParameter="{Binding ElementName=FilterTextBox, Path=Text}" />
就此5步,你的应用程序已经实现Command了。
附录 …
ProductViewModel的全部代码:
public class ProductViewModel : ViewModelBase { public ProductViewModel() { this.Products = new ObservableCollection<Product>(); // 注意: 这里只是代码示例 // ViewModel中不应为Model定义数据:-) // 我们可以通过调用服务得到Model所需数据. this.AllProducts = new ObservableCollection<Product>(); this.AllProducts.Add(new Product { ProductId = 1, ProductName = "Apple" }); this.AllProducts.Add(new Product { ProductId = 2, ProductName = "Orange" }); this.AllProducts.Add(new Product { ProductId = 3, ProductName = "Banana" }); this.AllProducts.Add(new Product { ProductId = 4, ProductName = "Pear" }); this.AllProducts.Add(new Product { ProductId = 5, ProductName = "Grape" }); this.AllProducts.Add(new Product { ProductId = 6, ProductName = "Grapefruit" }); this.AllProducts.Add(new Product { ProductId = 7, ProductName = "Strawberry" }); this.AllProducts.Add(new Product { ProductId = 8, ProductName = "Melon" }); this.AllProducts.Add(new Product { ProductId = 9, ProductName = "Guava" }); this.AllProducts.Add(new Product { ProductId = 10, ProductName = "Kiwi" }); this.AllProducts.Add(new Product { ProductId = 11, ProductName = "Pineapple" }); this.AllProducts.Add(new Product { ProductId = 12, ProductName = "Mango" }); LoadProductsCommand = new DelegateCommand(LoadProducts, CanLoadProducts); } private void LoadProducts(object param) { string filter = param as string ?? string.Empty; this.Products.Clear(); var query = from p in this.AllProducts where p.ProductName.ToLower().StartsWith(filter.ToLower()) select p; foreach (var item in query) { this.Products.Add(item); } } private bool CanLoadProducts(object param) { return true; } public ICommand LoadProductsCommand { get; set; } public ObservableCollection<Product> AllProducts { get; set; } private ObservableCollection<Product> products; public ObservableCollection<Product> Products { get { return products; } set { products = value; this.FirePropertyChanged("Product"); } } }
接下来是ViewModelBase类的全部代码,很简单的一个类,主要用来辅助包装PropertyChanged。
我项目中的所有ViewModel都继承了这个类。
public abstract class ViewModelBase : INotifyPropertyChanged { public ViewModelBase() { } public event PropertyChangedEventHandler PropertyChanged; protected void FirePropertyChanged(string propertyname) { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyname)); } }