• 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 之类的就另外开篇了。这篇也太长了。
    下面附上全部的代码:

    Xaml 代码:

     1 <Window x:Class="学习WpfDataGrid1.MainWindow"
     2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     6         mc:Ignorable="d"
     7         Title="MainWindow" Height="300" Width="250">
     8     <Grid >
     9         <Grid.RowDefinitions>
    10             <RowDefinition Height="24"/>
    11             <RowDefinition Height="5*"/>
    12             <RowDefinition Height="1*"/>
    13             <RowDefinition Height="1*"/>
    14             <RowDefinition Height="1*"/>
    15         </Grid.RowDefinitions>
    16         <Grid.ColumnDefinitions>
    17             <ColumnDefinition Width="1*"/>
    18             <ColumnDefinition Width="1*"/>
    19         </Grid.ColumnDefinitions>
    20         <CheckBox Name="chkResult" Content="查看数据" Margin="3" Grid.Row="0" Grid.Column="1" Click="chkResult_Click" />
    21         <ListBox Name="lbxData" Visibility="Hidden" Grid.Row="1" Grid.ColumnSpan="2"/>
    22         <ComboBox Name="cbbSelectMode" Margin="2" SelectionChanged="cbbSelectMode_SelectionChanged"/>
    23         <DataGrid Name="dtgShow" AutoGenerateColumns="False" Margin="3" Grid.Row="1" Grid.ColumnSpan="2" LoadingRow="dtgShow_LoadingRow" PreviewKeyDown="dtgShow_PreviewKeyDown" SelectedCellsChanged="dtgShow_SelectedCellsChanged" />
    24         <TextBox Name="tbxSelect" Grid.Row="2" Grid.ColumnSpan="2"/>
    25         <Button  Name="btnAppend" Content="Append" Margin="3" Grid.Row="3" Grid.Column="0" Click="btnAppend_Click" />
    26         <Button Name="btnRemoveLast" Content="Remove Last" Margin="3" Grid.Row="3" Grid.Column="1" Click="btnRemoveLast_Click"/>
    27         <Button  Name="btnInsert" Content="Insert" Margin="3" Grid.Row="4" Grid.Column="0" Click="btnInsert_Click" />
    28         <Button  Name="btnRemoveSelect" Content="Remove Selected" Margin="3" Grid.Row="4" Grid.Column="1" Click="btnRemoveSelect_Click" />
    29     </Grid>
    30 </Window>
    View Code

    C# 代码:

      1 using System.Collections.Generic;
      2 using System.Collections.ObjectModel;
      3 using System.Data;
      4 using System.Linq;
      5 using System.Text;
      6 using System.Windows;
      7 using System.Windows.Controls;
      8 using System.Windows.Data;
      9 using System.Windows.Input;
     10 
     11 namespace 学习WpfDataGrid1
     12 {
     13     /// <summary>
     14     /// MainWindow.xaml 的交互逻辑
     15     /// </summary>
     16     public partial class MainWindow : Window
     17     {
     18         List<int[]> list = new List<int[]>();
     19         ObservableCollection<int[]> showdata = new ObservableCollection<int[]>();
     20 
     21         public MainWindow()
     22         {
     23             InitializeComponent();
     24             AddSource();
     25             GetComboBoxSource();
     26             GetShowData();
     27         }
     28         //---原始数据源到显示数据源
     29         private void GetShowData()
     30         {
     31             showdata.Clear();
     32             foreach (var a in list)
     33             {
     34                 showdata.Add(a);
     35             }
     36             dtgShow.ItemsSource = showdata;
     37         }
     38         //---显示数据到原始数据
     39         private void GetRawData()
     40         {
     41             list.Clear();
     42             foreach (var a in showdata)
     43             {
     44                 list.Add(a);
     45             }
     46         }
     47         //---添加 ComboBox 数据源
     48         private void GetComboBoxSource()
     49         {
     50             //cbbSelectMode 为 ComboBox 控件实例
     51             cbbSelectMode.Items.Add(DataGridSelectionUnit.Cell);
     52             cbbSelectMode.Items.Add(DataGridSelectionUnit.FullRow);
     53             cbbSelectMode.Items.Add(DataGridSelectionUnit.CellOrRowHeader);
     54             cbbSelectMode.SelectedIndex = 2;
     55 
     56         }
     57         //---DataGrid 选择方式
     58         private void cbbSelectMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
     59         {
     60             dtgShow.SelectionUnit = (DataGridSelectionUnit)cbbSelectMode.SelectedValue;
     61         }
     62         //---添加 DataGrid 数据源
     63         private void AddSource()
     64         {
     65             list.Add(new int[] { 1, 2, 3, 4, 5 });
     66             list.Add(new int[] { 2, 3, 4, 5, 6 });
     67             list.Add(new int[] { 3, 4, 5, 6, 7 });
     68 
     69             int _col = list[0].Length;
     70             //int _row = list.Count;
     71             for (int i = 0; i < _col; i++)
     72             {
     73                 dtgShow.Columns.Add(new DataGridTextColumn
     74                 {
     75                     Width = (Width - 38) / _col,
     76                     Header = $"{(char)(65 + i)}",
     77                     Binding = new Binding($"[{i.ToString()}]")
     78                 });
     79             }
     80         }
     81         //---自动添加行号
     82         private void dtgShow_LoadingRow(object sender, DataGridRowEventArgs e)
     83         {
     84             e.Row.Header = e.Row.GetIndex() + 1;
     85         }
     86         //---Enter 达到 Tab 的效果
     87         private void dtgShow_PreviewKeyDown(object sender, KeyEventArgs e)
     88         {
     89             var uie = e.OriginalSource as UIElement;
     90             if (e.Key == Key.Enter)
     91             {
     92                 uie.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
     93                 e.Handled = true;
     94             }
     95         }
     96         //---给lbxData(ListBox) 添加数据
     97         private void GetListBoxSource()
     98         {
     99             lbxData.Items.Clear();
    100             StringBuilder sb = new StringBuilder();
    101             foreach (var a in list)
    102             {
    103                 sb.Clear();
    104                 foreach (var b in a)
    105                 {
    106                     sb.Append(b.ToString());
    107                     sb.Append(" ");
    108                 }
    109                 lbxData.Items.Add(sb.ToString());
    110             }
    111         }
    112         //---切换 DataGrid 和 ListBox
    113         private void chkResult_Click(object sender, RoutedEventArgs e)
    114         {
    115             CheckBox chk = (CheckBox)sender;
    116             if (chk.IsChecked == true)
    117             {
    118                 dtgShow.Visibility = Visibility.Hidden;
    119                 lbxData.Visibility = Visibility.Visible;
    120                 GetRawData();
    121                 GetListBoxSource();
    122             }
    123             else
    124             {
    125                 lbxData.Visibility = Visibility.Hidden;
    126                 dtgShow.Visibility = Visibility.Visible;
    127                 GetShowData();
    128             }
    129         }
    130         //增加新行
    131         private void btnAppend_Click(object sender, RoutedEventArgs e)
    132         {
    133             showdata.Add(new int[dtgShow.Columns.Count]);
    134         }
    135         //删除末行
    136         private void btnRemoveLast_Click(object sender, RoutedEventArgs e)
    137         {
    138             if (showdata.Count > 0)
    139             {
    140                 showdata.RemoveAt(showdata.Count - 1);
    141             }
    142         }
    143         //---取得选中 Cell 所在的行列
    144         private bool GetCellXY(DataGrid dg, ref int rowIndex, ref int columnIndex)
    145         {
    146             var _cells = dg.SelectedCells;
    147             if (_cells.Any())
    148             {
    149                 rowIndex = dg.Items.IndexOf(_cells.First().Item);
    150                 columnIndex = _cells.First().Column.DisplayIndex;
    151                 return true;
    152             }
    153             return false;
    154         }
    155         //在选中 Cell 所在行上插入新行
    156         private void btnInsert_Click(object sender, RoutedEventArgs e)
    157         {
    158             int _rowIndex = 0;
    159             int _columnIndex = 0;
    160             if (GetCellXY(dtgShow, ref _rowIndex, ref _columnIndex))
    161             {
    162                 showdata.Insert(_rowIndex, new int[dtgShow.Columns.Count]);
    163             }
    164         }
    165         //删除选中 Cell 所在行 
    166         private void btnRemoveSelect_Click(object sender, RoutedEventArgs e)
    167         {
    168             int _rowIndex = 0;
    169             int _columnIndex = 0;
    170             if (GetCellXY(dtgShow, ref _rowIndex, ref _columnIndex))
    171             {
    172                 showdata.RemoveAt(_rowIndex);
    173             }
    174         }
    175         //---获取所有的选中cell 的值
    176         private string GetSelectedCellsValue(DataGrid dg)
    177         {
    178             var cells = dg.SelectedCells;
    179             StringBuilder sb = new StringBuilder();
    180             if (cells.Any())
    181             {
    182                 foreach(var cell in cells)
    183                 {
    184                     sb.Append((cell.Column.GetCellContent(cell.Item) as TextBlock).Text);
    185                     sb.Append(" ");
    186                 }
    187             }
    188             return sb.ToString();
    189         }
    190         //---显示选中单元格的值
    191         private void dtgShow_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
    192         {
    193                 tbxSelect.Text = GetSelectedCellsValue(dtgShow);
    194         }
    195     }
    196 }
    View Code
  • 相关阅读:
    使用Google浏览器做真机页面调试
    JavaScript从作用域到闭包
    用canvas实现一个colorpicker
    你还在为移动端选择器picker插件而捉急吗?
    我是这样写文字轮播的
    高性能JS-DOM
    ExtJs4学习(四):Extjs 中id与itemId的差别
    MongoDB 安装与启动
    UML应用:业务内涵的分析抽象&amp;表达
    MySQL 错误日志(Error Log)
  • 原文地址:https://www.cnblogs.com/leemano/p/6436376.html
Copyright © 2020-2023  润新知