WPF DataGrid 控件的运用-灵活编辑、新增、删除列

WPF DataGrid 控件的运用

WPF DataGrid 控件的运用

运行环境:Window7 64bit,.NetFramework4.61,C# 6.0; 编者:乌龙哈里 2017-02-23


参考:

章节:

  • 添加列和数据源
  • 选择单位设置
  • 自动添加行号
  • Enter 键做成 Tab 键的效果
  • 同步更新数据源
  • 在选中 Cell 所在行上插入新行或删除选中 Cell 的所在行
  • 获取选中单元格的值

正文:

一、添加列和数据源:

我们往一个 DataGrid 中添加数据源 List< int[] >,注意要在 XAML 代码中把自动添加列的属性给设成 False, AutoGenerateColumns="False" 。

示例1:
C# 代码片段

List<int[]> list = new List<int[]>();
list.Add(new int[] { 1, 2, 3, 4, 5 });
list.Add(new int[] { 2, 3, 4, 5, 6 });
list.Add(new int[] { 3, 4, 5, 6, 7 });

int _col = list[0].Length;
int _row = list.Count;
for (int i = 0; i < _col; i++)
{
    dtgShow.Columns.Add(new DataGridTextColumn
    {
        Width = (Width - 30) / _col,
        Header = $"{(char)(65+i)}",
        Binding=new Binding($"[{i.ToString()}]")
     });
}
dtgShow.ItemsSource = list;

前端 XAML 片段:

<DataGrid Name="dtgShow" AutoGenerateColumns="False" Margin="3" Grid.Row="0" Grid.ColumnSpan="2"/>

二、选择单位设置:

DataGrid 的选择单位有3种,整行、单个 Cell 、单个 Cell 和 点行头选择整行。DataGrid 缺省状态是整行。我喜欢用第3种。

示例2:
C# 代码片段:

private void GetComboBoxSource()
{
    //cbbSelectMode 为 ComboBox 控件实例
    cbbSelectMode.Items.Add(DataGridSelectionUnit.Cell);
    cbbSelectMode.Items.Add(DataGridSelectionUnit.FullRow);
    cbbSelectMode.Items.Add(DataGridSelectionUnit.CellOrRowHeader);
}
private void cbbSelectMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    dtgShow.SelectionUnit = (DataGridSelectionUnit)cbbSelectMode.SelectedValue;
}

前端 Xaml 片段:

<ComboBox Name="cbbSelectMode" Margin="2" SelectionChanged="cbbSelectMode_SelectionChanged"/>

运行结果如图:

 

 

三、自动添加行号:

直接在 DataGrid 的 LoadingRow() 事件中写:

示例3:
C# 代码片段:

private void dtgShow_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Header = e.Row.GetIndex() + 1;
}

 

 

 

四、Enter 键做成 Tab 键的效果:

当 DataGrid 选择单位不是 FullRow 时,Enter 键后选择是下一行的 Cell,而选择下一个 Cell 用的是 Tab 键,对输入带来很大的不便。上面的参考中,流泉飞石的写法很简单(要把 KeyDown 事件换成 PreviewKeyDown),但不完美,显示效果不好,原先鼠标选择的蓝色方块并不会跟随回车键跳到下一个 Cell 上,要左右箭头动了才会动。Stackoverflow 论坛上有个 Using Enter Key as Tab in WPF DataGrid ,但选择项为 FullRow 时会出错,进入 Cell 的编辑状态回车就跳不出来了。看来还是流泉飞石的好。暂时先这样用了,以后再找更完美的。

示例4:

//Enter 达到 Tab 的效果
 private void dtgShow_PreviewKeyDown(object sender, KeyEventArgs e)
 {
     var uie = e.OriginalSource as UIElement;
     if (e.Key == Key.Enter)
     {
         uie.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
         e.Handled = true;
     }
 }

运行效果图,后面蓝色方块动是我左右键输入才动的:

 

五、同步更新数据源:

如果 DataGrid 里面的数据更新了,数据源数据也同步更新,最简单的做法就是用 ObservableCollection<T>类,记得要在前面 using System.Collections.ObjectModel; 要不要手工写通知的程序,有点麻烦。不多说了,上示例:

示例5:
C#代码片段:

List<int[]> list = new List<int[]>();
ObservableCollection<int[]> showdata = new ObservableCollection<int[]>();

//---原始数据源到显示数据源
private void GetShowData()
{
    showdata.Clear();
    foreach (var a in list)
    {
        showdata.Add(a);
    }
    dtgShow.ItemsSource = showdata;
}
//---显示数据到原始数据
private void GetRawData()
{
    list.Clear();
    foreach (var a in showdata)
    {
        list.Add(a);
    }
}

//---给lbxData(ListBox) 添加数据
private void GetListBoxSource()
{
    lbxData.Items.Clear();
    StringBuilder sb = new StringBuilder();
    foreach (var a in list)
    {
        sb.Clear();
        foreach (var b in a)
        {
            sb.Append(b.ToString());
            sb.Append(" ");
        }
        lbxData.Items.Add(sb.ToString());
    }
}
//---切换 DataGrid 和 ListBox
private void chkResult_Click(object sender, RoutedEventArgs e)
{
    CheckBox chk = (CheckBox)sender;
    if (chk.IsChecked==true)
    {
        dtgShow.Visibility = Visibility.Hidden;
        lbxData.Visibility = Visibility.Visible;
        GetRawData();
        GetListBoxSource();
    }
    else
    {
        lbxData.Visibility = Visibility.Hidden;
        dtgShow.Visibility = Visibility.Visible;
        GetShowData();
    }
}

Xaml 代码片段:

<Grid >
     <Grid.RowDefinitions>
         <RowDefinition Height="24"/>
         <RowDefinition Height="5*"/>
         <RowDefinition Height="1*"/>
     </Grid.RowDefinitions>
     <Grid.ColumnDefinitions>
         <ColumnDefinition Width="1*"/>
         <ColumnDefinition Width="1*"/>
     </Grid.ColumnDefinitions>
     <CheckBox Name="chkResult" Content="查看数据" Margin="3" Grid.Row="0" Grid.Column="1" Click="chkResult_Click" />
     <ListBox Name="lbxData" Visibility="Hidden" Grid.Row="1" Grid.ColumnSpan="2"/>
     <ComboBox Name="cbbSelectMode" Margin="2" SelectionChanged="cbbSelectMode_SelectionChanged"/>
     <DataGrid Name="dtgShow" AutoGenerateColumns="False" Margin="3" Grid.Row="1" Grid.ColumnSpan="2" LoadingRow="dtgShow_LoadingRow" PreviewKeyDown="dtgShow_PreviewKeyDown" />
     <Button Content="Add" Margin="3" Grid.Row="2" Grid.Column="0"/>
     <Button Content="Remove" Margin="3" Grid.Row="2" Grid.Column="1"/>
 </Grid>

 

六、在选中 Cell 的所在行上插入新行或删除选中的 Cell 所在行:

要解决这个主要就是找到所选 Cell 的行列序号,直接上程序:
示例6:

//增加新行
private void btnAppend_Click(object sender, RoutedEventArgs e)
{
    showdata.Add(new int[dtgShow.Columns.Count]);
}
//删除末行
private void btnRemoveLast_Click(object sender, RoutedEventArgs e)
{
    if (showdata.Count > 0)
    {
        showdata.RemoveAt(showdata.Count - 1);
    }
}
//---取得选中 Cell 所在的行列
private bool GetCellXY(DataGrid dg, ref int rowIndex, ref int columnIndex)
{
    var _cells = dg.SelectedCells;
    if (_cells.Any())
    {
        rowIndex = dg.Items.IndexOf(_cells.First().Item);
        columnIndex = _cells.First().Column.DisplayIndex;
        return true;
    }
    return false;
}
//在选中 Cell 所在行上插入新行
private void btnInsert_Click(object sender, RoutedEventArgs e)
{
    int _rowIndex = 0;
    int _columnIndex = 0;
    if(GetCellXY(dtgShow,ref _rowIndex,ref _columnIndex))
    {
        showdata.Insert(_rowIndex, new int[dtgShow.Columns.Count]);
    }
}
//删除选中 Cell 所在行 
private void btnRemoveSelect_Click(object sender, RoutedEventArgs e)
{
    int _rowIndex = 0;
    int _columnIndex = 0;
    if (GetCellXY(dtgShow, ref _rowIndex, ref _columnIndex))
    {
        showdata.RemoveAt(_rowIndex);
    }
}

 

 

七、获取选中单元格的值

方法一:在上面的示例6中知道了 Cell 的行列,通过 DataGrid 的绑定数据源取得数据;
方法二:DataGrid 每个单元格都是一个 TextBlock 控件,只要取得 TextBlock.Text 就能得到它的 String 值。
下面示例中,我们只需要显示数据,并不需要处理,所以选择方法二来运作。

示例7:

//---获取所有的选中cell 的值
private string GetSelectedCellsValue(DataGrid dg)
{
    var cells = dg.SelectedCells;
    StringBuilder sb = new StringBuilder();
    if (cells.Any())
    {
        foreach(var cell in cells)
        {
            sb.Append((cell.Column.GetCellContent(cell.Item) as TextBlock).Text);
            sb.Append(" ");
        }
    }
    return sb.ToString();
}
//---显示选中单元格的值
private void dtgShow_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
        tbxSelect.Text = GetSelectedCellsValue(dtgShow);
}

 

到此为止,DataGrid 的基本功能基本上摸得七七八八了,哦,还有一个功能是点击列的标题,DataGrid 会自动排序,不用自己实现了,真方便。剩下的像 样式之类的涉及到控件的 DataTemplate 之类的就另外开篇了。这篇也太长了。

下面附上全部的代码:

<Window x:Class="学习WpfDataGrid1.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"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="250">
    <Grid >
        <Grid.RowDefinitions>
            <RowDefinition Height="24"/>
            <RowDefinition Height="5*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
        <CheckBox Name="chkResult" Content="查看数据" Margin="3" Grid.Row="0" Grid.Column="1" Click="chkResult_Click" />
        <ListBox Name="lbxData" Visibility="Hidden" Grid.Row="1" Grid.ColumnSpan="2"/>
        <ComboBox Name="cbbSelectMode" Margin="2" SelectionChanged="cbbSelectMode_SelectionChanged"/>
        <DataGrid Name="dtgShow" AutoGenerateColumns="False" Margin="3" Grid.Row="1" Grid.ColumnSpan="2" LoadingRow="dtgShow_LoadingRow" PreviewKeyDown="dtgShow_PreviewKeyDown" SelectedCellsChanged="dtgShow_SelectedCellsChanged" />
        <TextBox Name="tbxSelect" Grid.Row="2" Grid.ColumnSpan="2"/>
        <Button  Name="btnAppend" Content="Append" Margin="3" Grid.Row="3" Grid.Column="0" Click="btnAppend_Click" />
        <Button Name="btnRemoveLast" Content="Remove Last" Margin="3" Grid.Row="3" Grid.Column="1" Click="btnRemoveLast_Click"/>
        <Button  Name="btnInsert" Content="Insert" Margin="3" Grid.Row="4" Grid.Column="0" Click="btnInsert_Click" />
        <Button  Name="btnRemoveSelect" Content="Remove Selected" Margin="3" Grid.Row="4" Grid.Column="1" Click="btnRemoveSelect_Click" />
    </Grid>
</Window>



using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;


namespace 学习WpfDataGrid1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        List<int[]> list = new List<int[]>();
        ObservableCollection<int[]> showdata = new ObservableCollection<int[]>();


        public MainWindow()
        {
            InitializeComponent();
            AddSource();
            GetComboBoxSource();
            GetShowData();
        }
        //---原始数据源到显示数据源
        private void GetShowData()
        {
            showdata.Clear();
            foreach (var a in list)
            {
                showdata.Add(a);
            }
            dtgShow.ItemsSource = showdata;
        }
        //---显示数据到原始数据
        private void GetRawData()
        {
            list.Clear();
            foreach (var a in showdata)
            {
                list.Add(a);
            }
        }
        //---添加 ComboBox 数据源
        private void GetComboBoxSource()
        {
            //cbbSelectMode 为 ComboBox 控件实例
            cbbSelectMode.Items.Add(DataGridSelectionUnit.Cell);
            cbbSelectMode.Items.Add(DataGridSelectionUnit.FullRow);
            cbbSelectMode.Items.Add(DataGridSelectionUnit.CellOrRowHeader);
            cbbSelectMode.SelectedIndex = 2;


        }
        //---DataGrid 选择方式
        private void cbbSelectMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            dtgShow.SelectionUnit = (DataGridSelectionUnit)cbbSelectMode.SelectedValue;
        }
        //---添加 DataGrid 数据源
        private void AddSource()
        {
            list.Add(new int[] { 1, 2, 3, 4, 5 });
            list.Add(new int[] { 2, 3, 4, 5, 6 });
            list.Add(new int[] { 3, 4, 5, 6, 7 });


            int _col = list[0].Length;
            //int _row = list.Count;
            for (int i = 0; i < _col; i++)
            {
                dtgShow.Columns.Add(new DataGridTextColumn
                {
                    Width = (Width - 38) / _col,
                    Header = $"{(char)(65 + i)}",
                    Binding = new Binding($"[{i.ToString()}]")
                });
            }
        }
        //---自动添加行号
        private void dtgShow_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.Header = e.Row.GetIndex() + 1;
        }
        //---Enter 达到 Tab 的效果
        private void dtgShow_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            var uie = e.OriginalSource as UIElement;
            if (e.Key == Key.Enter)
            {
                uie.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
                e.Handled = true;
            }
        }
        //---给lbxData(ListBox) 添加数据
        private void GetListBoxSource()
        {
            lbxData.Items.Clear();
            StringBuilder sb = new StringBuilder();
            foreach (var a in list)
            {
                sb.Clear();
                foreach (var b in a)
                {
                    sb.Append(b.ToString());
                    sb.Append(" ");
                }
                lbxData.Items.Add(sb.ToString());
            }
        }
        //---切换 DataGrid 和 ListBox
        private void chkResult_Click(object sender, RoutedEventArgs e)
        {
            CheckBox chk = (CheckBox)sender;
            if (chk.IsChecked == true)
            {
                dtgShow.Visibility = Visibility.Hidden;
                lbxData.Visibility = Visibility.Visible;
                GetRawData();
                GetListBoxSource();
            }
            else
            {
                lbxData.Visibility = Visibility.Hidden;
                dtgShow.Visibility = Visibility.Visible;
                GetShowData();
            }
        }
        //增加新行
        private void btnAppend_Click(object sender, RoutedEventArgs e)
        {
            showdata.Add(new int[dtgShow.Columns.Count]);
        }
        //删除末行
        private void btnRemoveLast_Click(object sender, RoutedEventArgs e)
        {
            if (showdata.Count > 0)
            {
                showdata.RemoveAt(showdata.Count - 1);
            }
        }
        //---取得选中 Cell 所在的行列
        private bool GetCellXY(DataGrid dg, ref int rowIndex, ref int columnIndex)
        {
            var _cells = dg.SelectedCells;
            if (_cells.Any())
            {
                rowIndex = dg.Items.IndexOf(_cells.First().Item);
                columnIndex = _cells.First().Column.DisplayIndex;
                return true;
            }
            return false;
        }
        //在选中 Cell 所在行上插入新行
        private void btnInsert_Click(object sender, RoutedEventArgs e)
        {
            int _rowIndex = 0;
            int _columnIndex = 0;
            if (GetCellXY(dtgShow, ref _rowIndex, ref _columnIndex))
            {
                showdata.Insert(_rowIndex, new int[dtgShow.Columns.Count]);
            }
        }
        //删除选中 Cell 所在行 
        private void btnRemoveSelect_Click(object sender, RoutedEventArgs e)
        {
            int _rowIndex = 0;
            int _columnIndex = 0;
            if (GetCellXY(dtgShow, ref _rowIndex, ref _columnIndex))
            {
                showdata.RemoveAt(_rowIndex);
            }
        }
        //---获取所有的选中cell 的值
        private string GetSelectedCellsValue(DataGrid dg)
        {
            var cells = dg.SelectedCells;
            StringBuilder sb = new StringBuilder();
            if (cells.Any())
            {
                foreach(var cell in cells)
                {
                    sb.Append((cell.Column.GetCellContent(cell.Item) as TextBlock).Text);
                    sb.Append(" ");
                }
            }
            return sb.ToString();
        }
        //---显示选中单元格的值
        private void dtgShow_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
        {
                tbxSelect.Text = GetSelectedCellsValue(dtgShow);
        }
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值