[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. 效果

 

由于上面所贴代码为完成代码,就不再另行上传项目了。

 

posted @ 2019-10-16 15:40  stonemqy  阅读(3017)  评论(0编辑  收藏  举报