規模稍大的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模式。