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

 

由於上面所貼代碼為完成代碼,就不再另行上傳項目了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM