本文是一个MVVM模式开发的基础教程,完全手写实现,未借助三方框架,适用于初学者
要实现DataGrid的编辑,步骤如下:
1、创建两个窗口,第一个窗口用于显示DataGrid,
布局如下:
这个界面上我们放置了一个DataGrid控件,并增加了三列,前面两列用于显示数据,最后一列用于编辑命令。
MainWindow.xaml
1 <Window x:Class="WPFDataGridEditDemo.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WPFDataGridEditDemo" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 <Grid> 10 <DataGrid x:Name="datagrid" ItemsSource="{Binding StudentCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" 11 CanUserAddRows="False" VerticalScrollBarVisibility="Hidden" IsReadOnly="True" Margin="20"> 12 <DataGrid.Columns> 13 <DataGridTextColumn Header="学号" Width="60" Binding="{Binding ID}"/> 14 <DataGridTextColumn Header="姓名" Width="*" Binding="{Binding Name}"/> 15 <DataGridTemplateColumn Header="操作" Width="120"> 16 <DataGridTemplateColumn.CellTemplate> 17 <DataTemplate> 18 <StackPanel Orientation="Horizontal"> 19 <TextBlock Margin="0,0,5,0"> 20 <Hyperlink Command="{Binding EditCommand}" CommandParameter="{Binding ElementName=datagrid,Path=SelectedItem}">编辑</Hyperlink> 21 </TextBlock> 22 </StackPanel> 23 </DataTemplate> 24 </DataGridTemplateColumn.CellTemplate> 25 </DataGridTemplateColumn> 26 </DataGrid.Columns> 27 </DataGrid> 28 </Grid> 29 </Window>
2、创建一个编辑窗口,这个窗口用于编辑字段值
DataEditView.xaml
1 <Window x:Class="WPFDataGridEditDemo.Views.DataEditView" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WPFDataGridEditDemo.Views" 7 mc:Ignorable="d" 8 Title="DataEditView" Height="450" Width="800"> 9 <Grid> 10 <Border> 11 <Grid Background="Transparent"> 12 <TabControl BorderThickness="0" Margin="0,5"> 13 <TabItem Header="学生信息" FontSize="12"> 14 <Grid> 15 <Grid.ColumnDefinitions> 16 <ColumnDefinition/> 17 <ColumnDefinition Width="1.6*"/> 18 </Grid.ColumnDefinitions> 19 <Grid> 20 <Grid.RowDefinitions> 21 <RowDefinition Height="40"/> 22 <RowDefinition/> 23 </Grid.RowDefinitions> 24 25 <TextBlock Text="姓名" Margin="18,0" VerticalAlignment="Center"/> 26 </Grid> 27 <Grid Grid.Column="1"> 28 <Grid.RowDefinitions> 29 <RowDefinition Height="40"/> 30 <RowDefinition/> 31 </Grid.RowDefinitions> 32 33 <TextBox Grid.Row="0" Text="{Binding Name}" Height="23" VerticalContentAlignment="Center" Width="220"/> 34 <Button Grid.Row="6" Content="保存" Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="10" 35 CommandParameter="{Binding .,RelativeSource={RelativeSource AncestorType=Window}}" Background="LightBlue" Command="{Binding SaveCommand}" /> 36 </Grid> 37 </Grid> 38 </TabItem> 39 </TabControl> 40 </Grid> 41 </Border> 42 </Grid> 43 </Window>
3、定义一下MVVM中使用的命令对象CommandBase类
1 public class CommandBase : ICommand 2 { 3 public event EventHandler CanExecuteChanged; 4 5 public bool CanExecute(object parameter) 6 { 7 return true; 8 } 9 10 public void Execute(object parameter) 11 { 12 DoExecute?.Invoke(parameter); 13 } 14 15 public Action<object> DoExecute { get; set; } 16 }
4、创建一个用于DataGrid显示的数据模型Student,数据模型的字段名要跟DataGrid的列名绑定的属性名对应。
1 public class Student : INotifyPropertyChanged 2 { 3 public event PropertyChangedEventHandler PropertyChanged; 4 5 public void NotifyChanged([CallerMemberName] string propName = "") 6 { 7 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));//全局通知(给监听此属性的控件) 8 } 9 10 private int id; 11 private string name; 12 13 public int ID 14 { 15 get => id; 16 set 17 { 18 id = value; 19 NotifyChanged(); 20 } 21 } 22 23 public string Name 24 { 25 get => name; 26 set 27 { 28 name = value; 29 NotifyChanged(); 30 } 31 } 32 33 private CommandBase editCommand; 34 35 public CommandBase EditCommand 36 { 37 get 38 { 39 if (editCommand == null) 40 { 41 editCommand = new CommandBase(); 42 editCommand.DoExecute = new Action<object>(obj => { 43 //预留 44 }); 45 } 46 return editCommand; 47 } 48 49 }
5、为界面创建ViewModel,ViewModel里增加一个用于显示到DataGrid的列表属性StudentCollection
1 public class MainWindowViewModel : INotifyPropertyChanged 2 { 3 public event PropertyChangedEventHandler PropertyChanged; 4 5 public void RaiseChanged([CallerMemberName] string propertyName = "") 6 { 7 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 8 } 9 10 private ObservableCollection<Student> studentCollection = new ObservableCollection<Student>(); 11 12 public ObservableCollection<Student> StudentCollection 13 { 14 get => this.studentCollection; 15 set 16 { 17 studentCollection = value; 18 this.RaiseChanged(); 19 } 20 } 21 }
6、构造一个测试数据,并将ViewModel绑定到主窗口的DataContext上。
1 public partial class MainWindow : Window 2 { 3 public MainWindow() 4 { 5 InitializeComponent(); 6 7 var mainviewmodel = new MainWindowViewModel(); 8 9 mainviewmodel.StudentCollection.Add(new Model.Student() { ID = 1, Name = "标签111111" }); 10 mainviewmodel.StudentCollection.Add(new Model.Student() { ID = 2, Name = "标签222222" }); 11 12 13 this.DataContext = mainviewmodel; 14 } 15 }
7、运行,可以看到界面显示如下:
8、增加编辑功能
需要为编辑界面增加一个ViewModel,在这个ViewModel中定义显示在界面上的字段,并增加一个保存命令
1 public class DataEditViewModel : INotifyPropertyChanged 2 { 3 public event PropertyChangedEventHandler PropertyChanged; 4 5 public void RaiseChanged([CallerMemberName] string propName = "") 6 { 7 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); 8 } 9 10 private int id; 11 private string name; 12 13 public int Num 14 { 15 get => id; 16 set 17 { 18 id = value; 19 RaiseChanged(); 20 } 21 } 22 23 public string Name 24 { 25 get => name; 26 set 27 { 28 name = value; 29 RaiseChanged(); 30 } 31 } 32 33 private CommandBase saveCommand; 34 public CommandBase SaveCommand 35 { 36 get 37 { 38 if (saveCommand == null) 39 { 40 saveCommand = new CommandBase(); 41 saveCommand.DoExecute = new Action<object>(obj => { 42 var window = obj as Window; 43 44 if (window != null) 45 window.DialogResult = true; 46 }); 47 } 48 49 return saveCommand; 50 } 51 } 52 }
9、回到前面定义的Student类,将EditCommand补全
因为一个数据对象就是表格的一行,所以这个编辑命令需要定义在实体类中。
1 public CommandBase EditCommand 2 { 3 get 4 { 5 if (editCommand == null) 6 { 7 editCommand = new CommandBase(); 8 editCommand.DoExecute = new Action<object>(obj => { 9 var connectData = obj as Student; 10 DataEditView dataEditView = new DataEditView(); 11 DataEditViewModel dataEditViewModel = new DataEditViewModel(); 12 dataEditViewModel.Num = connectData.ID; 13 dataEditViewModel.Name = connectData.Name; 14 dataEditView.DataContext = dataEditViewModel; 15 16 if(dataEditView.ShowDialog() == true) 17 { 18 connectData.ID = dataEditViewModel.Num; 19 connectData.Name = dataEditViewModel.Name; 20 } 21 }); 22 } 23 return editCommand; 24 } 25 26 }
10、单击编辑链接,就可以弹出 一个新窗口进行编辑,编辑完成后,数据会更新到DataGrid中去。
示例代码