[源码下载]

背水一战 Windows 10 (23) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令

作者:webabcd

介绍
背水一战 Windows 10 之 MVVM(Model-View-ViewModel)

  • 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令

示例
1、Model
MVVM/Model/Product.cs

/*
* Model 层的实体类,如果需要通知则需要实现 INotifyPropertyChanged 接口
*/ using System.ComponentModel; namespace Windows10.MVVM.Model
{
public class Product : INotifyPropertyChanged
{
public Product()
{
ProductId = ;
Name = "";
Category = "";
} private int _productId;
public int ProductId
{
get { return _productId; }
set
{
_productId = value;
RaisePropertyChanged(nameof(ProductId));
}
} private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
RaisePropertyChanged(nameof(Name));
}
} private string _category;
public string Category
{
get { return _category; }
set
{
_category = value;
RaisePropertyChanged(nameof(Category));
}
} public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
}

MVVM/Model/ProductDatabase.cs

/*
* Model 层的数据持久化操作(本地或远程)
*
* 本例只是一个演示
*/ using System;
using System.Collections.Generic;
using System.Linq; namespace Windows10.MVVM.Model
{
public class ProductDatabase
{
private List<Product> _products = null; public List<Product> GetProducts()
{
if (_products == null)
{
Random random = new Random(); _products = new List<Product>(); for (int i = ; i < ; i++)
{
_products.Add
(
new Product
{
ProductId = i,
Name = "Name" + i.ToString().PadLeft(, ''),
Category = "Category" + (char)random.Next(, )
}
);
}
} return _products;
} public List<Product> GetProducts(string name, string category)
{
return GetProducts().Where(p => p.Name.Contains(name) && p.Category.Contains(category)).ToList();
} public void Update(Product product)
{
var oldProduct = _products.Single(p => p.ProductId == product.ProductId);
oldProduct = product;
} public Product Add(string name, string category)
{
Product product = new Product();
product.ProductId = _products.Max(p => p.ProductId) + ;
product.Name = name;
product.Category = category; _products.Insert(, product); return product;
} public void Delete(Product product)
{
_products.Remove(product);
}
}
}

2、ViewModel
MVVM/ViewModel1/MyCommand.cs

/*
* 为了方便使用,把 ICommand 再封装一层
*/ using System;
using System.Windows.Input; namespace Windows10.MVVM.ViewModel1
{
public class MyCommand : ICommand
{
// 由 public void Execute(object parameter) 调用的委托
public Action<object> MyExecute { get; set; } // 由 public bool CanExecute(object parameter) 调用的委托
public Func<object, bool> MyCanExecute { get; set; } public MyCommand(Action<object> execute, Func<object, bool> canExecute)
{
this.MyExecute = execute;
this.MyCanExecute = canExecute;
} // 需要发布此事件的话,则调用 RaiseCanExecuteChanged 方法即可
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
} // 用于决定当前绑定的 Command 能否被执行
// parameter 是由 ButtonBase 的 CommandParameter 传递过来的
// 如果返回 false 则对应的 ButtonBase 将变为不可用
public bool CanExecute(object parameter)
{
return this.MyCanExecute == null ? true : this.MyCanExecute(parameter);
} // 用于执行对应的命令,只有在 CanExecute() 返回 true 时才可以被执行
// parameter 是由 ButtonBase 的 CommandParameter 传递过来的对象
public void Execute(object parameter)
{
this.MyExecute(parameter);
}
}
}

MVVM/ViewModel1/ProductViewModel.cs

/*
* ViewModel 层
*
* 注:为了方便使用,此例对 ICommand 做了一层封装。如果需要了解比较原始的 MVVM 实现请参见 http://www.cnblogs.com/webabcd/archive/2013/08/29/3288304.html
*/ using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using Windows10.MVVM.Model; namespace Windows10.MVVM.ViewModel1
{
public class ProductViewModel : INotifyPropertyChanged
{
// 用于提供 Products 数据
private ObservableCollection<Product> _products;
public ObservableCollection<Product> Products
{
get { return _products; }
set
{
_products = value;
RaisePropertyChanged(nameof(Products));
}
} // 用于“添加”和“查询”的 Product 对象
private Product _product;
public Product Product
{
get { return _product; }
set
{
_product = value;
RaisePropertyChanged(nameof(Product));
}
} // 数据库对象
private ProductDatabase _context = null; public ProductViewModel()
{
_context = new ProductDatabase(); Product = new Product();
Products = new ObservableCollection<Product>(_context.GetProducts());
} private MyCommand _getProductsCommand;
public MyCommand GetProductsCommand
{
get
{
return _getProductsCommand ?? (_getProductsCommand = new MyCommand
((object obj) =>
{
// 从 Model 层获取数据
Products = new ObservableCollection<Product>(_context.GetProducts(Product.Name, Product.Category));
},
null));
}
} private MyCommand _addProductCommand;
public MyCommand AddProductCommand
{
get
{
return _addProductCommand ?? (_addProductCommand = new MyCommand
((object obj) =>
{
// 在 Model 层添加一条数据
Product newProduct = _context.Add(Product.Name, Product.Category); // 更新 ViewModel 层数据
Products.Insert(, newProduct);
},
null));
}
} private MyCommand _updateProductCommand;
public MyCommand UpdateProductCommand
{
get
{
return _updateProductCommand ?? (_updateProductCommand = new MyCommand
((object obj) =>
{
// 通过 CommandParameter 传递过来的数据
Product product = obj as Product; // 更新 ViewModel 层数据
product.Name = product.Name + "U";
product.Category = product.Category + "U"; // 更新 Model 层数据
_context.Update(product);
},
// 对应 ICommand 的 CanExecute(),如果返回 false 则对应的 ButtonBase 将变为不可用
(object obj) => obj != null));
}
} private MyCommand _deleteProductCommand;
public MyCommand DeleteProductCommand
{
get
{
return _deleteProductCommand ?? (_deleteProductCommand = new MyCommand
((object obj) =>
{
// 通过 CommandParameter 传递过来的数据
Product product = obj as Product; // 更新 Model 层数据
_context.Delete(product); // 更新 ViewModel 层数据
Products.Remove(product);
},
// 对应 ICommand 的 CanExecute(),如果返回 false 则对应的 ButtonBase 将变为不可用
(object obj) => obj != null));
}
} public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
}

3、View
MVVM/View/Demo1.xaml

<Page
x:Class="Windows10.MVVM.View.Demo1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows10.MVVM.View"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" xmlns:vm="using:Windows10.MVVM.ViewModel1"> <Grid Background="Transparent">
<StackPanel Margin="10 0 10 10"> <!--
View 层
--> <!--
本例通过 Binding 结合 Command 实现 MVVM(用 x:Bind 结合 Command 实现 MVVM 也是一样的),通过 ButtonBase 触发命令
--> <StackPanel.DataContext>
<vm:ProductViewModel />
</StackPanel.DataContext> <ListView Name="listView" ItemsSource="{Binding Products}" Width="300" Height="300" HorizontalAlignment="Left" VerticalAlignment="Top">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" HorizontalAlignment="Left" />
<TextBlock Text="{Binding Category}" HorizontalAlignment="Left" Margin="10 0 0 0" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView> <StackPanel Orientation="Horizontal" Margin="0 10 0 0" DataContext="{Binding Product}">
<TextBlock Text="Name:" VerticalAlignment="Center" />
<TextBox Name="txtName" Text="{Binding Name, Mode=TwoWay}" Width="100" />
<TextBlock Text="Category:" VerticalAlignment="Center" Margin="20 0 0 0" />
<TextBox Name="txtCategory" Text="{Binding Category, Mode=TwoWay}" Width="100" />
</StackPanel> <!--
ButtonBase
Command - 指定关联的 ICommand
CommandParameter - 传递给 ICommand 的参数
-->
<StackPanel Orientation="Horizontal" Margin="0 10 0 0">
<Button Name="btnSearch" Content="查询" Command="{Binding GetProductsCommand}" Margin="10 0 0 0" />
<Button Name="btnAdd" Content="添加" Command="{Binding AddProductCommand}" Margin="10 0 0 0" />
<Button Name="btnUpdate" Content="更新" Command="{Binding UpdateProductCommand}" CommandParameter="{Binding SelectedItem, ElementName=listView}" Margin="10 0 0 0" />
<Button Name="btnDelete" Content="删除" Command="{Binding DeleteProductCommand}" CommandParameter="{Binding SelectedItem, ElementName=listView}" Margin="10 0 0 0" />
</StackPanel> </StackPanel>
</Grid>
</Page>

OK
[源码下载]

背水一战 Windows 10 (23) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令的更多相关文章

  1. 背水一战 Windows 10 (24) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令

    [源码下载] 背水一战 Windows 10 (24) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令 作者:webabcd ...

  2. 背水一战 Windows 10 (25) - MVVM: 通过 x:Bind 实现 MVVM(不用 Command)

    [源码下载] 背水一战 Windows 10 (25) - MVVM: 通过 x:Bind 实现 MVVM(不用 Command) 作者:webabcd 介绍背水一战 Windows 10 之 MVV ...

  3. 背水一战 Windows 10 (22) - 绑定: 通过 Binding 绑定对象, 通过 x:Bind 绑定对象, 通过 Binding 绑定集合, 通过 x:Bind 绑定集合

    [源码下载] 背水一战 Windows 10 (22) - 绑定: 通过 Binding 绑定对象, 通过 x:Bind 绑定对象, 通过 Binding 绑定集合, 通过 x:Bind 绑定集合 作 ...

  4. 背水一战 Windows 10 (119) - 后台任务: 后台下载任务(任务分组,组完成后触发后台任务)

    [源码下载] 背水一战 Windows 10 (119) - 后台任务: 后台下载任务(任务分组,组完成后触发后台任务) 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下 ...

  5. MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令

    介绍背水一战 Windows 10 之 MVVM(Model-View-ViewModel) 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令 ...

  6. MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令

    介绍背水一战 Windows 10 之 MVVM(Model-View-ViewModel) 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令 ...

  7. 背水一战 Windows 10 (120) - 后台任务: 后台上传任务

    [源码下载] 背水一战 Windows 10 (120) - 后台任务: 后台上传任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台上传任务 示例演示 uwp 的后台上 ...

  8. 背水一战 Windows 10 (118) - 后台任务: 后台下载任务(任务分组,并行或串行执行,组完成后通知)

    [源码下载] 背水一战 Windows 10 (118) - 后台任务: 后台下载任务(任务分组,并行或串行执行,组完成后通知) 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 ...

  9. 背水一战 Windows 10 (117) - 后台任务: 后台下载任务

    [源码下载] 背水一战 Windows 10 (117) - 后台任务: 后台下载任务 作者:webabcd 介绍背水一战 Windows 10 之 后台任务 后台下载任务 示例演示 uwp 的后台下 ...

随机推荐

  1. [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦

    [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...

  2. C# Random生成多个不重复的随机数万能接口

    C#,Radom.Next()提供了在一定范围生成一个随机数的方法,我现在有个业务场景是给其他部门推送一些数据供他们做抽样检查处理,假设我的数据库里面有N条数据,现在要定期给其随机推送数据,我需要先拿 ...

  3. spring事务管理器设计思想(二)

    上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当前没有事务,就新建一个事务.这是最常见 ...

  4. 如何创建一个AJAX-Enabled WCF Service

      原创地址:http://www.cnblogs.com/jfzhu/p/4041638.html 转载请注明出处   前面的文章中介绍过<Step by Step 创建一个WCF Servi ...

  5. rem单位和em单位的使用

    今天弄了一点响应式的东西,本以为很快就可以弄好,结果还是绕晕了头,所以还是写下来方便下次看吧! 一开始我打算用百分比%来做响应式布局,后来算的很懵圈,就果断放弃了,哈哈是不是很明智. 接下来就是rem ...

  6. 使用easyui-layout布局

    <body class="easyui-layout"> <div data-options="region:'north',title:'顶部',sp ...

  7. IOS 开发中 Whose view is not in the window hierarchy 错误的解决办法

    在 IOS 开发当中经常碰到 whose view is not in the window hierarchy 的错误,该错误简单的说,是由于 "ViewController" ...

  8. JAVA的静态变量、静态方法、静态类

    静态变量和静态方法都属于静态对象,它与非静态对象的差别需要做个说明. (1)Java静态对象和非静态对象有什么区别? 比对如下: 静态对象                                ...

  9. Android数据存储之Sqlite的介绍及使用

    前言: 本来没有打算整理有关Sqlite数据库文章的,最近一直在研究ContentProvider的使用,所有觉得还是先对Sqlite进行一个简单的回顾,也方便研究学习ContentProvider. ...

  10. Objective-C中的语法糖

    写这篇博客源于一个疑问:“WoK~, 这也行?!”.刚接触OC不久,今天做深浅拷贝的测试,无意中把获取NSArray的值写成了用下标获取的方式.当时把注意力放在了深浅拷贝的内存地址分析上了,就没太在意 ...