WPF DataGrid显格式
Guide to WPF DataGrid formatting using bindings
Introduction
Formatting WPF DataGrid content depending on business logic data is way too difficult. Especially since MSDN is not telling you anything about it. I have spent weeks to figure out how to get the binding right. Let me show you how it is done to save you time and endless searches on the Internet.
WPF DataGrid Structure
The container hierarchy of a DataGrid looks like this:
DataGrid
DataGridRows
DataGridCell
TextBlock
A DataGrid contains DataGridRow
s which contain DataGridCell
s which contain exactly one TextBlock
, if it is a TextColumn
and in read mode (editing mode uses a TextBox
). Of course, the visual tree is a bit more complicated:
Note that DataGridColumn
is not part of the visual tree. Whatever is defined in DataGridColumn
will be applied to all cells of that column.
WPF Binding Basics
The binding gets assigned to a FrameworkElement
property, which constitutes the target of the binding.
WPF needs two source information to make a binding work:
- Source: Which object provides the information
- Path: Which property of the source should be used
Usually, the Source gets inherited from the DataContext
of a parent container, often the Window itself. But DataGrid's DataContext
cannot be used for the binding of rows and cells, because each row needs to bind to a different business logic object.
DataGridColumn
specifies the binding for the value to be displayed in the cell with the DataGridColumn.Binding
property. The DataGrid creates during runtime a binding for every TextBlock.Text
. Unfortunately, the DataGrid
does not support binding for any other property of TextBlock
. If you try to setup a style for the TextBlock
yourself, the binding will most likely fail, because it wouldn't know which business object from the ItemsSource
to use.
Business data used
The business data example is based on some stock taking figures. A stock item looks like this:
public class StockItem {
public string Name { get; set; }
public int Quantity { get; set; }
public bool IsObsolete { get; set; }
}
The sample data:
Name | Quantity | IsObsolete |
Many items | 100 | false |
Enough items | 10 | false |
Shortage item | 1 | false |
Item with error | -1 | false |
Obsolete item | 200 | true |
Connecting a DataGrid with business data
Even connecting a DataGrid with the business data is not trivial. Basically, a CollectionViewSource
is used to connect the DataGrid with the business data:
The CollectionViewSource
does the actual data navigation, sorting, filtering, etc.
- Define a
CollectionViewSource
inWindows.Resource
<Window.Resources>
<CollectionViewSource x:Key="ItemCollectionViewSource" CollectionViewType="ListCollectionView"/>
</Window.Resources>
- The gotcha here is that you
must
- set the
CollectionViewType
- . If you don't, the GridView will use
BindingListCollectionView
- , which does not support sorting. Of course, MSDN does not explain this anywhere.
- Set the
DataContext
of the DataGrid to theCollectionViewSource
.
<DataGrid
DataContext="{StaticResource ItemCollectionViewSource}"
ItemsSource="{Binding}"
AutoGenerateColumns="False"
CanUserAddRows="False">
- In the code behind, find the
CollectionViewSource
and assign your business data to the Source property
//create business data
var itemList = new List<stockitem>();
itemList.Add(new StockItem {Name= "Many items", Quantity=100, IsObsolete=false});
itemList.Add(new StockItem {Name= "Enough items", Quantity=10, IsObsolete=false});
... //link business data to CollectionViewSource
CollectionViewSource itemCollectionViewSource;
itemCollectionViewSource = (CollectionViewSource)(FindResource("ItemCollectionViewSource"));
itemCollectionViewSource.Source = itemList;</stockitem>
In this article, data gets only read. If the user should be able to edit the data, use an ObservableCollection
.
DataGrid Formatting
Formatting a column
Formatting a whole column is easy. Just set the property, like Fontweight
directly in the DataGridColumn
:
<DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" FontWeight="Bold"/>
The binding here is not involved with the formatting, but specifies the content of the cell (i.e., Text
property of TextBlock
).
Formatting complete rows
Formatting the rows is special, because there will be many rows. The DataGrid
offers for this purpose the RowStyle
property. This style will be applied to every DataGridRow
.
<datagrid.rowstyle>
<style targettype="DataGridRow">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self},
Path=Item.Quantity, Converter={StaticResource QuantityToBackgroundConverter}}"/>
</style>
</datagrid.rowstyle>
The DatGridRow
has an Item property, which contains the business logic object for that row. The binding for the DataRow
must therefore bind to itself ! The path is a bit surprising, because Item is of type Object
and doesn't know any business data properties. But the WPF binding applies a bit of magic and finds the Quantity
property of StockItem
anyway.
In this example, the background of a row depends on the value of the Quantity
property of the business object. If there are many items in stock, the background should be white, if only few are left, the background should be grey. The QuantityToBackgroundConverter
performs the necessary calculation:
class QuantityToBackgroundConverter: IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
if (value is int) {
int quantity = (int)value;
if (quantity>=100) return Brushes.White;
if (quantity>=10) return Brushes.WhiteSmoke;
if (quantity>=0) return Brushes.LightGray;
return Brushes.White; //quantity should not be below 0
}
//value is not an integer. Do not throw an exception
// in the converter, but return something that is obviously wrong
return Brushes.Yellow;
} public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
Formatting a cell based on the displayed value
Formatting just a cell instead of the whole row is a challenge. In a text column, the cell has a TextBlock
which needs to be styled. To create a Style
for TextBlock
s is easy, but how can the TextBlock
property be bound to the proper business object ? The DataGrid is binding already the Text
property of the TextBlock
. If the styling depends only on the cell value, we can simply use a self binding to this Text property.
Example: In our stock grid, the Quantity
should always be greater than or equal zero. If a quantity is negative, it is an error and should be displayed in red:
<Setter Property="Foreground"
Value="{Binding
RelativeSource={RelativeSource Self},
Path=Text,
Converter={StaticResource QuantityToForegroundConverter}}" />
Formatting a cell based on business logic data
The most complex case is if the cell format does not depend on the cell value, but some other business data. In our example, the quantity of an item should be displayed as strike through if it is obsolete. To achieve this, the TextDecorations
property needs to be linked to the business object of that row. Meaning the TextBlock
has to find the parent DataGridRow
. Luckily, binding to a parent visual object can be done with a relative source:
<Setter Property="TextDecorations"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}},
Path =Item.IsObsolete,
Converter={StaticResource IsObsoleteToTextDecorationsConverter}}" />
public class IsObsoleteToTextDecorationsConverter: IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
if (value is bool) {
if ((bool)value) {
TextDecorationCollection redStrikthroughTextDecoration =
TextDecorations.Strikethrough.CloneCurrentValue();
redStrikthroughTextDecoration[0].Pen = new Pen {Brush=Brushes.Red, Thickness = 3 };
return redStrikthroughTextDecoration;
}
}
return new TextDecorationCollection();
} public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
Code
See the Zip file for the complete source code of the sample.
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
Share
WPF DataGrid显格式的更多相关文章
- WPF DataGrid常用属性记录
WPF DataGrid常用属性记录 组件常用方法: BeginEdit:使DataGrid进入编辑状态. CancelEdit:取消DataGrid的编辑状态. CollapseRowGroup:闭 ...
- WPF DATAGRID - COMMITTING CHANGES CELL-BY-CELL
In my recent codeproject article on the DataGrid I described a number of techniques for handling the ...
- WPF DataGrid某列使用多绑定后该列排序失效,列上加入 SortMemberPath 设置即可.
WPF DataGrid某列使用多绑定后该列排序失效 2011-07-14 10:59hdongq | 浏览 1031 次 悬赏:20 在wpf的datagrid中某一列使用了多绑定,但是该列排序失 ...
- xceed wpf datagrid
<!--*********************************************************************************** Extended ...
- 获取wpf datagrid当前被编辑单元格的内容
原文 获取wpf datagrid当前被编辑单元格的内容 确认修改单元个的值, 使用到datagrid的两个事件 开始编辑事件 BeginningEdit="dataGrid_Beginni ...
- WPF DataGrid绑定一个组合列
WPF DataGrid绑定一个组合列 前台: <Page.Resources> <local:InfoConverter x:Key="converter& ...
- WPF DataGrid自定义样式
微软的WPF DataGrid中有很多的属性和样式,你可以调整,以寻找合适的(如果你是一名设计师).下面,找到我的小抄造型的网格.它不是100%全面,但它可以让你走得很远,有一些非常有用的技巧和陷阱. ...
- WPF DataGrid Custommization using Style and Template
WPF DataGrid Custommization using Style and Template 代码下载:http://download.csdn.net/detail/wujicai/81 ...
- 编写 WPF DataGrid 列模板,实现更好的用户体验
Julie Lerman 下载代码示例 最近我在为一个客户做一些 Windows Presentation Foundation (WPF) 方面的工作. 虽然我提倡使用第三方工具,但有时也会避免使用 ...
随机推荐
- Day-10: 错误、调试和测试
程序运行时,会遇到各种各样的错误. 编写错误叫做bug,而另一类由于运行过程中无法预测的,比如写文件时,磁盘满了,写不进去:或者从网络抓取数据,网络突然掉了.这些错误称为异常,程序中需要对异常进行处理 ...
- 误删libc.os.6共享库的解决办法
在我们使用系统的过程中,要注意各个共享库的使用,万一不小心删掉了什么,就可能出现各种问题.如果你把libc.os.6删掉了,那可就悲剧了,因为你的大部分命令都不能够正常使用了(╥╯^╰╥) 接下来呢, ...
- ospf剩余笔记
OSPF 流程图: 带宽 开销 10 100 100 19 1000 4 10000 2 区域的划分减少lsdb的大小 有利于网络管理员故障排除 网络故障不会影响到其他区域 邻接关系 ...
- sublime编辑器代码背景刺眼怎么修改?
有些人觉得如上图大括号刺眼,怎么把它改得不那么刺眼呢? [第一步]打开Bracket Hightlighter插件的用户配置文件: 然后按ctrl+G跳转到第330行, 如图位置改为"sty ...
- 201521123103 《Java学习笔记》 第四周学习总结
一.本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. (1)多态性:相同形态,不同行为(不同的定义): (2)多态绑定:运行时能够自动地选择调用哪个 ...
- 201521123110第二周Java学习总结
1.本章学习总结 本周的Java学习相对前一周更进了一步,初步学习了Java简单的输入和输出,String类的对象创建后不能修改,它是不可变的,在Java中浮点型默认是double型与C中的int型不 ...
- 三分钟深入TT猫之故障转移
结束了一周繁忙的工作,趁着周末,小编手中的键盘早已饥渴难耐了,想知道上期省略号中发生了什么有趣的故事么?且听小编娓娓道来,结尾有彩蛋. 目录 风月前场 梦回现实 模拟老鸨 会话机制 故障转移 总结 风 ...
- Java项目生成Jar文件
打开 Jar 文件向导 Jar 文件向导可用于将项目导出为可运行的 jar 包. 打开向导的步骤为: 在 Package Explorer 中选择你要导出的项目内容.如果你要导出项目中所有的类和资源, ...
- 03标准对象-01-Date和JSON
0.写在前面的话 在JS世界中,一切都是对象,区别对象类型使用tyepof,返回一个字符串,如: typeof 123; // 'number' typeof NaN; // 'number' typ ...
- uvalive 3971 Assemble
https://vjudge.net/problem/UVALive-3971 题意: 现在你要组装一台电脑,每个电脑的一种类型的配件都有多种选择,它们的名字是不同的. 现在给出已有的元件,每种类型都 ...