本文是一个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 }