[WPF] 操作DataGrid单元格
1. 源起
今天想用WPF的DataGrid控件,实现如下功能:
如上图,表格有四列:序号、名称、别名、操作。其中名称列固定,不可修改;别名列可以修改。点击【修改】按钮后,按钮标题变为【完成】,对应的别名列单元格显示文本框,文本框内默认显示原有的别名;点击【完成】按钮,文本框消失,单元格内显示为修改后的别名,按钮标题变为【修改】。
2. 实现
新建一个WPF窗体Window2,Window2.xaml如下:
<Window x:Class="WpfApp1.Window2" 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" mc:Ignorable="d" Title="Window2" Height="300" Width="400" Loaded="Window2_OnLoaded"> <Window.Resources> <Style TargetType="Button"> <Setter Property="Foreground" Value="#37acf4"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="BorderBrush" Value="#37acf4"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ButtonBase"> <Border x:Name="bd" CornerRadius="2" BorderBrush="{x:Null}" BorderThickness="0" Background="{TemplateBinding Background}"> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"> <Border BorderThickness="0,0,0,1" BorderBrush="{TemplateBinding BorderBrush}"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/> </Border> </StackPanel> </Border> <ControlTemplate.Triggers> <Trigger Property="IsEnabled" Value="False"> <Setter Property="Foreground" Value="#999"/> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="bd" Property="Background" Value="Transparent"/> <Setter Property="Cursor" Value="Hand"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <DataGrid x:Name="DataGrid" AutoGenerateColumns="False" ItemsSource="{Binding DataList}" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserResizeColumns="False" CanUserSortColumns="False" CanUserReorderColumns="False" CanUserAddRows="False"> <DataGrid.Columns> <DataGridTextColumn Header="序号" Binding="{Binding Id}" Width="60"/> <DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="*"/> <DataGridTemplateColumn Header="别名" Width="*"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid> <TextBlock x:Name="Block" Text="{Binding AliasName}" VerticalAlignment="Center" HorizontalAlignment="Center"/> <TextBox x:Name="Box" Text="{Binding AliasName,UpdateSourceTrigger=LostFocus}" Width="100" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Collapsed"/> </Grid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Header="操作" Width="100"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Grid> <Button Content="修改" Tag="{Binding Id}" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Edit_OnClick"/> </Grid> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </Grid> </Window>
Window2.xaml.cs:
using System; using System.Windows; using System.Windows.Controls; using WpfApp1.ViewModels; namespace WpfApp1 { /// <summary> /// Window2.xaml 的交互逻辑 /// </summary> public partial class Window2 : Window { private WindowViewModel _view; public Window2() { InitializeComponent(); _view = new WindowViewModel(); DataContext = _view; } private void Window2_OnLoaded(object sender, RoutedEventArgs e) { _view.Init(); } private void Edit_OnClick(object sender, RoutedEventArgs e) { if (!(sender is Button btn)) return; if (btn.Tag == null) return; var id = 0; // 数据源模型的Id肩负着DataGrid中行号的作用 if (!int.TryParse(btn.Tag.ToString(), out id)) return; var columns = DataGrid.Columns; var column = columns[2]; var cell = column.GetCellContent(DataGrid.Items[id - 1]); var grid = cell.GetVisualChild<Grid>(); var title = btn.Content.ToString(); foreach (FrameworkElement child in grid.Children) { if (child.Name == "Block") { if (title == "修改") child.Visibility = Visibility.Collapsed; else if (title == "完成") child.Visibility = Visibility.Visible; } else if (child.Name == "Box") { if (title == "修改") child.Visibility = Visibility.Visible; else if (title == "完成") child.Visibility = Visibility.Collapsed; } } if (title == "修改") btn.Content = "完成"; else if (title == "完成") btn.Content = "修改"; } } }
WindowViewModel:
using System.Collections.Generic; using WpfApp1.Common; using WpfApp1.Models; namespace WpfApp1.ViewModels { public class WindowViewModel : PropertyChangedBase { private List<TestViewModel> _dataList = new List<TestViewModel>(); public List<TestViewModel> DataList { get => _dataList; set => SetValue(ref _dataList, value, nameof(DataList)); } public void Init() { DataList.Add(new TestViewModel { Id = 1, Name = "电机电压", AliasName = "电压" }); DataList.Add(new TestViewModel { Id = 2, Name = "电机电流", AliasName = "电流" }); DataList.Add(new TestViewModel { Id = 3, Name = "电机功率", AliasName = "功率" }); DataList.Add(new TestViewModel { Id = 4, Name = "电机温度", AliasName = "温度" }); } } }
PropertyChangedBase:
using System.Collections.Generic; using System.ComponentModel; namespace WpfApp1.Common { /// <summary> /// 用于通知属性变更的基类 /// </summary> public class PropertyChangedBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public void SetValue<T>(ref T field, T value, string propertyName) { if (EqualityComparer<T>.Default.Equals(field, value)) return; field = value; OnPropertyChanged(propertyName); } } }
TestViewModel:
using WpfApp1.Common; namespace WpfApp1.Models { public class TestViewModel : PropertyChangedBase { private int _id; public int Id { get => _id; set => SetValue(ref _id, value, nameof(Id)); } private string _name = ""; public string Name { get => _name; set => SetValue(ref _name, value, nameof(Name)); } private string _aliasName = ""; public string AliasName { get => _aliasName; set => SetValue(ref _aliasName, value, nameof(AliasName)); } private bool _isSelected; public bool IsSelected { get => _isSelected; set => SetValue(ref _isSelected, value, nameof(IsSelected)); } } }
至此,完成了所有需求。
3. 效果
由于上面所贴代码为完成代码,就不再另行上传项目了。
学到的就要教人