顾名思义,DataGrid 是用来显示数据的控件,从对象集合获取信息并在具有行和单元格的网格中显示信息。每行和单独的对象队列,并且每列和对象的某个属性相对应。
DataGrid 控件添加了许多在WPF中处数据所需的技能。其基于列的模型提供了显著的格式化灵活性。其选择模型运行选择一行、多行或一些单元格的组合。其编辑支持非常强大,可使用DataGrid 控件作为简单数据和复杂数据的统一数据编辑器。
AutoGenerateColumns
当指定AutoGenerateColumns=“True”时,会使用自动生成列功能,该值的默认值为True。当给DataGrid指定了数据源ItemsSource 后,DataGrid 控件使用反射查找绑定对象中的每个公有属性,并为每个属性创建一列。
定义列
使用自动生成的列,可快速创建显示所有数据的DataGrid 控件,但放弃了一些控制能力。例如,不能控制列的顺序、每列的宽度、如何格式化列中的值以及应该放在顶部的标题文本的内容。
目前,DataGrid 控件支持几种类型的列,通过继承自DataGridColumn 的不同类表示这些列:
DataGridTextColumn 这种列对于大部分数据类型是标准选择。值被转换为文本,并在TextBook 元素中显示。当编辑行时,TextBlock 元素被替换为标准的文本框 TextBox。
DataGridCheckBoxColumn 这种列显示复选框。为bool值自动使用这种类型。通常,复选框是只读的;但当编辑行时,会变成普通的复选框。
DataGridHyperlinkColumn 这种列显示可单击的连接。如果结合使用WPF中的导航容器,如Frame或NavigationWindow,可允许用户导航到其它URI。
DataGridComboBoxColumn 最初这种列看起来与DataGridTextColumn 类似,但在编辑模式下这种列会变成下拉的 ComboBox 控件。当希望将编辑限制于允许的少部分值时,这种列是很好的选择。
在将DataGridComboBoxColumn绑定到枚举值时,为了避免硬编码,可以通过ObjectDataProvider来提供子项的内容,在ItemsSource 中指定在资源中定义的 ObjectDataProvider 即可。
DataGridTemplateColumn 这种列是目前为止功能最强大的选择。这种列允许为显示列值定义数据模板,具有在列表控件中使用模板时所具有的所有灵活性和功能。
设置列的格式和样式
可以使用与设置TextBlock元素格式相同的方式设置 DataGridTextColumn 元素的格式,方法就是设置 Foreground、FontFamily、FontSize、FontStyle以及FontWeight 属性。然而,DataGridTextColumn 没有提供TextBlock 的所有属性。
本质上,ElementStyle 属性用于创建应用于DataGrid 单元格内部的元素样式。对于简单的 DataGridTextColumn,该元素是 TextBlock,对于DataGridCheckBoxColumn ,单元格内部的元素是复选框,可使用 EditingElementStyle 属性为编辑列时使用的元素提供样式。对于DataGridTextColumn,编辑元素是 TextBox 控件。
设置行格式
通过设置DataGrid 列对象的属性,可控制如何格式化整个列。但在许多情况下,标识包含特定数据的行更有用。可以通过DataGrid.LoadingRow 事件以编程方式应用此类格式。对于设置行格式,LoadingRow 事件是一个非常强大的工具。它提供了对当前行数据对象的访问,允许开发人员执行简单的范围检查、比较以及更复杂的操作。它还提供了行的 DataGridRow 对象,允许开发人员使用不同的颜色或不同的字体设置行的格式。
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
if (e.Row.DataContext is Order order)
{
if (order.Price > 1000)
e.Row.Background = highlightBrush;
else
e.Row.Background = normalBrush;
}
}
显示细节
DataGrid 控件还支持行细节——一块可选 的独立显示区域,在行的列值的下面显示。行细节区域添加了无法仅使用库尔实现的两个特征:
1、能够跨越 DataGrid 控件宽度,并且不会切入到独立的列中,从而提供了更多可供使用的空间。
2、可配置行细节区域,从而只为选择的行显示该区域,当不需要时允许用户折叠额外的细节。
冻结列
只需设置FrozenColumnCount 冻结列数,即可设置冻结列,冻结的列必须总是位于网格的左侧。
选择
与普通的列表控件类似,DataGrid 控件允许用户选择单个项。当选择一项时,可以响应 SelectionChanged 事件。为找到当前选择的数据对象,可使用 SelectedItem 属性。如果希望用户能选择多行,将SelectionMode 属性设置为 Extended。
排序
DataGrid 控件内置了排序功能,只要绑定的数据源实现了IList 接口,如 List
编辑
DataGrid 控件最方便之处在于支持编辑。当用户双击DataGrid单元格时,改单元格会切换到编辑模式。单DataGrid 控件以几种方式限制这种编辑功能:
1、DataGrid.IsReadOnly 当该属性为True时,用户不能编辑任何内容。
2、DataGridColumn.IsReadOnly 当该属性为True时,用户不能编辑该列中的任何值。
3、只读属性, 如果数据对象具有没有属性设置器的属性,DataGrid 控件能够注意到该细节,并禁用该列编辑,就相当于设置了 DataGridColumn.IsReadOnly 为 True 一样。类似的,如果属性不是简单的文本、数字或日期类型,DataGrid控件使其为只读(可以切换到 DataGridTemplateColumn 来补救这种情况,如前面介绍DataGridTemplateColumn 时的例子,给列设定 DataGridTemplateColumn.CellEditingTemplate 模板)。
MainWindow.xaml
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace TestDataGrid;
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual bool SetProperty(ref T member, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer.Default.Equals(member, value))
{
return false;
}
member = value;
OnPropertyChanged(propertyName);
return true;
}
}
public enum DirectionType
{
Buy = 0,
Sell = 1,
}
public class Order : ViewModelBase
{
private bool isSelected;
public bool IsSelected { get => isSelected; set => SetProperty(ref isSelected, value); }
private DirectionType directionType;
public DirectionType Direction { get => directionType; set => SetProperty(ref directionType, value); }
private string urlTest = string.Empty;
public string UrlTest { get => urlTest; set => SetProperty(ref urlTest, value); }
private string description = "Binding is a markup extension. When you use the binding extension to declare a binding, the declaration consists of a series of clauses following the Binding keyword and separated by commas (,). The clauses in the binding declaration can be in any order and there are many possible combinations. The clauses are Name=Value pairs, where Name is the name of the Binding property and Value is the value you're setting for the property.";
public string Description { get => description; set => SetProperty(ref description, value); }
private decimal price = 0;
public decimal Price { get => price; set => SetProperty(ref price, value); }
private int volume = 0;
public int Volume { get => volume; set => SetProperty(ref volume, value); }
private DateTime orderDate = DateTime.Now;
public DateTime OrderDate { get => orderDate; set => SetProperty(ref orderDate, value); }
private string image = string.Empty;
public string Image { get => image; set => SetProperty(ref image, value); }
}
public class ImagePathConverter : IValueConverter
{
private string imageDirectory = Directory.GetCurrentDirectory();
public string ImageDirectory
{
get { return imageDirectory; }
set { imageDirectory = value; }
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string imagePath = Path.Combine(ImageDirectory, (string)value);
return new BitmapImage(new Uri(imagePath));
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("The method or operation is not implemented.");
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
myGrid.DataContext = Orders;
InitOrder();
}
public ObservableCollection Orders { get; set; } = new();
private SolidColorBrush highlightBrush = new SolidColorBrush(Colors.Orange);
private SolidColorBrush normalBrush = new SolidColorBrush(Colors.White);
public void InitOrder()
{
Order order1 = new Order();
Order order2 = new Order();
Order order3 = new Order();
Order order4 = new Order();
order1.IsSelected = true;
order1.Direction = DirectionType.Buy;
order1.UrlTest = "https://www.baidu.com/";
order1.Price = 100;
order1.Volume = 10;
order1.Image = "image1.gif";
order2.IsSelected = true;
order2.Direction = DirectionType.Buy;
order2.UrlTest = "https://www.baidu.com/";
order2.Price = 1000;
order2.Volume = 100;
order2.Image = "image2.gif";
order3.IsSelected = false;
order3.Direction = DirectionType.Sell;
order3.UrlTest = "https://www.baidu.com/";
order3.Price = 10000;
order3.Volume = 1000;
order3.Image = "image3.gif";
order4.IsSelected = false;
order4.Direction = DirectionType.Sell;
order4.UrlTest = "https://www.baidu.com/";
order4.Price = 100000;
order4.Volume = 10000;
order4.Image = "image4.gif";
Orders.Add(order1);
Orders.Add(order2);
Orders.Add(order3);
Orders.Add(order4);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
if (e.Row.DataContext is Order order)
{
if (order.Price > 1000)
e.Row.Background = highlightBrush;
else
e.Row.Background = normalBrush;
}
}
}