规模稍大的WPF项目一般会采用MVVM模式,常见的框架有Prism、MvvmLight、Caliburn等。今天就从头开始创建一个使用MVVM模式的WPF项目,对MVVM也能有一个更好的了解。
1.实现INotifyPropertyChanged接口
实现INotifyPropertyChanged接口是为了利用WPF的数据绑定特性,当数据源发生变化时,能及时通知UI层进行刷新,避免手动刷新UI的问题。
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected internal virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
2.实现ICommand接口
WPF默认的交互方式是事件驱动的,即UI层的动作触发路由事件,数据层在路由事件的函数中进行相应处理。实现ICommand接口是为了将UI层和数据层解耦,避免绑定路由事件时的强关联。
public class DelegateCommands<T> : ICommand
{
private readonly Action<T> _executeMethod = null;
private readonly Func<T, bool> _canExecuteMethod = null;
public DelegateCommands(Action<T> executeMethod)
: this(executeMethod, null)
{ }
public DelegateCommands(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
{
if (executeMethod == null)
throw new ArgumentNullException("executeMetnod");
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
}
#region ICommand 成员
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute(T parameter)
{
if (_canExecuteMethod != null)
{
return _canExecuteMethod(parameter);
}
return true;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute(T parameter)
{
if (_executeMethod != null)
{
_executeMethod(parameter);
}
}
#endregion
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
#region ICommand 成员
public bool CanExecute(object parameter)
{
if (parameter == null && typeof(T).IsValueType)
{
return (_canExecuteMethod == null);
}
return CanExecute((T)parameter);
}
public void Execute(object parameter)
{
Execute((T)parameter);
}
#endregion
}
3.创建ViewModel
新建MainWindowViewModel类,继承自上面的ViewModelBase类,用于命令的绑定触发和数据的处理通知。
public class MainWindowViewModel:ViewModelBase
{
public MainWindowViewModel()
{
//命令绑定
AddCommand = new DelegateCommands<string>(Add);
EditCommand = new DelegateCommands<DetailGoodsDto>(Edit);
DeleteCommand = new DelegateCommands<DetailGoodsDto>(Delete);
//数据初始化
InitData();
}
#region Properties-属性
private List<DetailGoodsDto> _goodsList;
public List<DetailGoodsDto> GoodsList
{
get { return _goodsList; }
set
{
if (_goodsList != value)
{
_goodsList = value;
OnPropertyChanged("GoodsList");
}
}
}
#endregion
#region Commands-命令
public DelegateCommands<string> AddCommand { get; set; }
public DelegateCommands<DetailGoodsDto> EditCommand { get; set; }
public DelegateCommands<DetailGoodsDto> DeleteCommand { get; set; }
#endregion
#region Methods-方法
private void InitData()
{
GoodsList = new List<DetailGoodsDto>()
{
new DetailGoodsDto
{
GoodsName="矿泉水",
GoodsType="酒水饮料",
Location="1号库",
GoodsNum=100
}
};
}
private void Add(string obj)
{
//to do
}
private void Edit(DetailGoodsDto obj)
{
//to do
}
private void Delete(DetailGoodsDto obj)
{
//to do
}
#endregion
}
4.修改View并绑定数据上下文
修改MainWindow.xaml,与MainWindowViewModel中的属性和命令一一对应。
<Window x:Class="AbpDemo.Client.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AbpDemo.Client"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Right">
<Button Command="{Binding AddCommand}" CommandParameter="Add">添加</Button>
<Button Command="{Binding EditCommand}" CommandParameter="{Binding ElementName=GoodsData,Path=SelectedItem}">编辑</Button>
<Button Command="{Binding DeleteCommand}" CommandParameter="{Binding ElementName=GoodsData,Path=SelectedItem}">删除</Button>
</WrapPanel>
<DataGrid x:Name="GoodsData" Grid.Row="1" AutoGenerateColumns="False" SelectionUnit="FullRow" ItemsSource="{Binding GoodsList}">
<DataGrid.Columns>
<DataGridTextColumn Header="货品名称" Width="*" Binding="{Binding GoodsName}"></DataGridTextColumn>
<DataGridTextColumn Header="货品类型" Width="*" Binding="{Binding GoodsType}"></DataGridTextColumn>
<DataGridTextColumn Header="存放位置" Width="*" Binding="{Binding Location}"></DataGridTextColumn>
<DataGridTextColumn Header="货品数量" Width="*" Binding="{Binding GoodsNum}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
同时修改MainWindow.xaml.cs以建立View视图层与ViewModel视图模型层的关联关系。
public partial class MainWindow : Window
{
private MainWindowViewModel _viewModel;
public MainWindow()
{
_viewModel = new MainWindowViewModel();
this.DataContext = _viewModel;//设置数据上下文
InitializeComponent();
}
}
以上步骤就完成了最简单的MVVM模式。