WPF 如何在 MVVM模式下实现 DataGrid编辑功能

前言

在WPF开发中,DataGrid是一个非常常用的控件,用于展示和操作表格数据。而MVVM(Model-View-ViewModel)模式则是WPF推荐的开发架构,它将界面逻辑与业务逻辑分离,提高了代码的可维护性和可测试性。

本文将手把手带你实现一个基于MVVM模式的DataGrid编辑功能,不依赖任何第三方框架,适合初学者理解和学习。

正文

要实现DataGrid的编辑功能,我们需要创建两个窗口:一个用于显示数据,另一个用于编辑数据。以下是具体的实现步骤。

1、创建主窗口用于显示DataGrid

我们首先创建一个MainWindow,其中包含一个DataGrid控件,用于显示学生信息。

布局如下:

MainWindow.xaml

xml 复制代码
<Window x:Class="WPFDataGridEditDemo.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:WPFDataGridEditDemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <DataGrid x:Name="datagrid" ItemsSource="{Binding StudentCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False"
          CanUserAddRows="False" VerticalScrollBarVisibility="Hidden" IsReadOnly="True" Margin="20">
            <DataGrid.Columns>
                <DataGridTextColumn Header="学号" Width="60" Binding="{Binding ID}"/>
                <DataGridTextColumn Header="姓名" Width="*" Binding="{Binding Name}"/>
                <DataGridTemplateColumn Header="操作" Width="120">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Margin="0,0,5,0">
                                    <Hyperlink Command="{Binding EditCommand}" CommandParameter="{Binding ElementName=datagrid,Path=SelectedItem}">编辑</Hyperlink>
                                </TextBlock>
                            </StackPanel>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

2、创建编辑窗口

接下来,我们创建一个DataEditView窗口,用于编辑学生信息。

布局如下:

DataEditView.xaml

xml 复制代码
<Window x:Class="WPFDataGridEditDemo.Views.DataEditView"
        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:WPFDataGridEditDemo.Views"
        mc:Ignorable="d"
        Title="DataEditView" Height="450" Width="800">
    <Grid>
        <Border>
            <Grid Background="Transparent">
                <TabControl BorderThickness="0" Margin="0,5">
                    <TabItem Header="学生信息" FontSize="12">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition/>
                                <ColumnDefinition Width="1.6*"/>
                            </Grid.ColumnDefinitions>
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="40"/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <TextBlock Text="姓名" Margin="18,0" VerticalAlignment="Center"/>
                            </Grid>
                            <Grid Grid.Column="1">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="40"/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <TextBox Grid.Row="0" Text="{Binding Name}" Height="23" VerticalContentAlignment="Center" Width="220"/>
                                <Button Grid.Row="6" Content="保存"  Width="88" Height="28" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="10"
                                CommandParameter="{Binding .,RelativeSource={RelativeSource AncestorType=Window}}" Background="LightBlue" Command="{Binding SaveCommand}" />
                            </Grid>
                        </Grid>
                    </TabItem>
                </TabControl>
            </Grid>
        </Border>
    </Grid>
</Window>

3、定义命令对象

为了实现命令绑定,我们需要定义一个CommandBase类,实现ICommand接口:

csharp 复制代码
public class CommandBase : ICommand
{
    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        DoExecute?.Invoke(parameter);
    }

    public Action<object> DoExecute { get; set; }
}

4、创建数据模型

创建一个Student类,实现INotifyPropertyChanged接口,以便在属性变化时通知UI更新:

csharp 复制代码
public class Student : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyChanged([CallerMemberName] string propName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }

    private int id;
    private string name;

    public int ID 
    {
        get => id; 
        set
        {
            id = value;
            NotifyChanged();
        }
    }

    public string Name
    { 
        get => name;
        set
        {
            name = value;
            NotifyChanged();
        }
    }

    private CommandBase editCommand;

    public CommandBase EditCommand
    {
        get
        {
            if (editCommand == null)
            {
                editCommand = new CommandBase();
                editCommand.DoExecute = new Action<object>(obj => {
                   //预留
                });
            }
            return editCommand;
        }
    }
}

5、创建ViewModel

为MainWindow创建一个ViewModel,包含一个StudentCollection属性,用于绑定到DataGrid:

csharp 复制代码
public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void RaiseChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private ObservableCollection<Student> studentCollection = new ObservableCollection<Student>();

    public ObservableCollection<Student> StudentCollection
    {
        get => this.studentCollection;
        set
        {
            studentCollection = value;
            this.RaiseChanged();
        }
    }
}

6、绑定ViewModel

在MainWindow的构造函数中,创建ViewModel实例,并添加测试数据:

csharp 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var mainviewmodel = new MainWindowViewModel();

        mainviewmodel.StudentCollection.Add(new Model.Student() { ID = 1, Name = "标签111111" });
        mainviewmodel.StudentCollection.Add(new Model.Student() { ID = 2, Name = "标签222222" });

        this.DataContext = mainviewmodel;
    }
}

7、实现编辑功能

为编辑窗口创建一个ViewModel,包含保存命令:

csharp 复制代码
public class DataEditViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void RaiseChanged([CallerMemberName] string propName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }

    private int id;
    private string name;

    public int Num
    {
        get => id;
        set
        {
            id = value;
            RaiseChanged();
        }
    }

    public string Name
    {
        get => name;
        set
        {
            name = value;
            RaiseChanged();
        }
    }

    private CommandBase saveCommand;
    public CommandBase SaveCommand
    {
        get
        {
            if (saveCommand == null)
            {
                saveCommand = new CommandBase();
                saveCommand.DoExecute = new Action<object>(obj => {
                    var window = obj as Window;

                    if (window != null)
                        window.DialogResult = true;
                });
            }

            return saveCommand;
        }
    }
}

8、补全编辑命令

在Student类中补全EditCommand,实现点击"编辑"时弹出编辑窗口:

csharp 复制代码
public CommandBase EditCommand
{
    get
    {
        if (editCommand == null)
        {
            editCommand = new CommandBase();
            editCommand.DoExecute = new Action<object>(obj => {
                var connectData = obj as Student;
                DataEditView dataEditView = new DataEditView();
                DataEditViewModel dataEditViewModel = new DataEditViewModel();
                dataEditViewModel.Num = connectData.ID;
                dataEditViewModel.Name = connectData.Name;
                dataEditView.DataContext = dataEditViewModel;

                if(dataEditView.ShowDialog() == true)
                {
                    connectData.ID = dataEditViewModel.Num;
                    connectData.Name = dataEditViewModel.Name;
                }
            });
        }
        return editCommand;
    }
}

运行程序,点击"编辑"链接,即可弹出编辑窗口,修改数据后保存,数据会自动更新到DataGrid中。

总结

通过以上步骤,我们实现了基于MVVM模式的DataGrid编辑功能。整个过程不依赖任何第三方框架,代码清晰易懂,适合初学者学习和理解MVVM模式的基本原理。关键在于正确使用数据绑定、命令和通知机制,将界面逻辑与业务逻辑分离,提高代码的可维护性。

关键词

WPF、MVVM、DataGrid、编辑、命令、数据绑定、ViewModel

相关推荐
锅包一切2 小时前
二、几种安装类型
linux·运维·后端·操作系统
Hoffer_2 小时前
更好理解ORDER BY内部排序和性能优化-mysql
后端·mysql
游乐码2 小时前
c#扩展方法
开发语言·c#
Penge6662 小时前
Go 语言 defer:你需要掌握的三个核心要点
后端
言午说数据2 小时前
Spark SQL练习2-电商用户行为分析
后端
Loo国昌3 小时前
【AI应用开发实战】04_混合检索器:BM25+向量+可靠度融合实战
人工智能·后端·python·自然语言处理
先做个垃圾出来………3 小时前
Flask框架特点对比
后端·python·flask
人道领域3 小时前
SpringBoot整合Junit与Mybatis实战
java·spring boot·后端
今天你TLE了吗3 小时前
JVM学习笔记:第四章——虚拟机栈
java·jvm·笔记·后端·学习