MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令
介绍
背水一战 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 = 0;
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 = 0; i < 100; i++)
{
_products.Add
(
new Product
{
ProductId = i,
Name = "Name" + i.ToString().PadLeft(4, '0'),
Category = "Category" + (char)random.Next(65, 91)
}
);
}
} 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) + 1;
product.Name = name;
product.Category = category; _products.Insert(0, 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(0, 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_2.xaml

<Page
x:Class="Windows10.MVVM.View.Demo1_2"
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:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core" 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, UpdateSourceTrigger=PropertyChanged}" Width="100" />
<TextBlock Text="Category:" VerticalAlignment="Center" Margin="20 0 0 0" />
<TextBox Name="txtCategory" Text="{Binding Category, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="100" />
</StackPanel> <!--
需要引用 Microsoft.Xaml.Interactions.dll 和 Microsoft.Xaml.Interactivity.dll Microsoft.Xaml.Interactions.Core:EventTriggerBehavior
EventName - 关联的事件名称 Microsoft.Xaml.Interactions.Core:InvokeCommandAction
Command - 指定关联的 ICommand
CommandParameter - 传递给 ICommand 的参数
-->
<StackPanel Orientation="Horizontal" Margin="0 10 0 0">
<TextBlock Text="查询">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Core:InvokeCommandAction Command="{Binding GetProductsCommand}" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</TextBlock> <TextBlock Text="添加" Margin="10 0 0 0">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Core:InvokeCommandAction Command="{Binding AddProductCommand}" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</TextBlock> <TextBlock Text="更新" Margin="10 0 0 0">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Core:InvokeCommandAction Command="{Binding UpdateProductCommand}" CommandParameter="{Binding SelectedItem, ElementName=listView}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</TextBlock> <TextBlock Text="删除" Margin="10 0 0 0">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Core:InvokeCommandAction Command="{Binding DeleteProductCommand}" CommandParameter="{Binding SelectedItem, ElementName=listView}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</TextBlock>
</StackPanel> </StackPanel>
</Grid>
</Page>
MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令的更多相关文章
- 背水一战 Windows 10 (23) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令
[源码下载] 背水一战 Windows 10 (23) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令 作者:webabcd ...
- MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令
介绍背水一战 Windows 10 之 MVVM(Model-View-ViewModel) 通过 Binding 或 x:Bind 结合 Command 实现,通过 ButtonBase 触发命令 ...
- 背水一战 Windows 10 (24) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令
[源码下载] 背水一战 Windows 10 (24) - MVVM: 通过 Binding 或 x:Bind 结合 Command 实现,通过非 ButtonBase 触发命令 作者:webabcd ...
- How to bind a Command on a ContextMenu within a DataTemplate using MVVM
Since the Popuup control has it's separate visual tree, you cannot use find ancestor to find the Gri ...
- MySQL在command line Client下的一些命令
MySQL在command line Client下的一些命令 通过CMD进入到本地数据库: mysql -h localhost -u -root -p 参数说明: -h 要连接的服务器的主机名或I ...
- Linux 输入指令显示 command not found(未找到命令)解决办法
问题摘要:当我在linux中安装了一个Nginx,最后需要检查是否安装成功的时候,输入了Nginx -v 提示未找到命令(服务器中英文提示为 command not found) 其他软件命令未找到问 ...
- (WPF, MVVM) Slider Binding.
对于Button的Command的绑定可以通过实现ICommand接口来进行,但是Slider并没有Command属性. 另外如果要实现MVVM模式的话,需要将一些Method和Slider的Even ...
- MVVM模式应用 之为ApplicationBarIconButton 添加Command操作属性
在学习MVVM的过程中,总是会遇到挫折,一碰到就是花费好长时间去解决..唉,不求量,只求质. 第一种(已经实践成功): (1)http://bindableapplicationb.codeplex. ...
- (WPF, MVVM) Textbox Binding
参考:http://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger(v=vs.110).aspx Te ...
随机推荐
- luogu[1279]字串距离
题目描述 设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□”和“abcb□cd□”都是X ...
- JavaScript 全局属性/函数
JavaScript 全局 JavaScript 全局属性和方法可用于创建Javascript对象. JavaScript 全局属性 属性 描述 Infinity 代表正的无穷大的数值. NaN 指示 ...
- css中如何设置字体
来自百度的回答: 建议使用font-family: "Microsoft YaHei";支持UTF-8和GB2312字符集. 不生效的3种情况:1.当此属性定义的是全局样式时,对于 ...
- BZOJ 2733 【HNOI2012】 永无乡
Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...
- codevs 1907 方格取数 3
Description 在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. Input 第 ...
- 玩转Android Camera开发(二):使用TextureView和SurfaceTexture预览Camera 基础拍照demo
Google自Android4.0出了TextureView,为什么推出呢?就是为了弥补Surfaceview的不足,另外一方面也是为了平衡GlSurfaceView,当然这是本人揣度的.关于Text ...
- MVC UpdateModel的未能更新XXXXX的类型模型
关于MVC UpdateModel的未能更新XXXXX的类型模型 的问题: 最近做MVC3的项目,相信很多人都碰到过这个问题,在此记录一下,异常:UpdateModel的未能更新XXXXX的类型模型 ...
- ORACLE 定时执行存储过程
推荐用dbms_scheduler方式更好 (2012-11-19注) /* 查询: select job,broken,what,interval,t.* from user_jobs t; job ...
- JavaScript的一些知识碎片(1)
打算把使用Javascript的水平从child提升到小学毕业,近期会持续记录一些知识点. javascript的引用机制:只要一个对象赋值为另一个对象,就建立了引用.一旦建立了引用,对象们就公用一块 ...
- ASP.MVC EASY UI 入门之 —— Tree & ComboTree
1.常规的EASY UI的tree和comboTree代码基本是官方的DEMO都有的,虽然很简单,但是还是要实践的做一次,才能更清晰的了解和使用它!先上效果图 因为用的是code first,所以数据 ...