2KB项目,专业的源码交易网站 帮助 收藏 每日签到

WPF DataGrid 使用绑定来对数据进行格式化

  • 时间:2019-01-23 18:38 编辑:2KB 来源:2KB.COM 阅读:469
  • 扫一扫,手机访问
  • 分享
摘要:
WPF 英文原文:Guide to WPF DataGrid formatting using bindings

简介

将基于WPF框架的数据表格内的业务逻辑数据格式化是非常复杂的过程,尤其是当MSDN没有提供提供任何帮助的时候。我花了数周的时间弄清了如何正确绑定数据,下面我的讲解将会帮助你终止无尽的搜索和浪费时间。

WPF 数据表格结构 

作为容器的数据表格层次差不多就是下面这样了:

数据表(DataGrid )
  行(DataGridRows)
     单元格(DataGridCell)
       文本块(TextBlock  )

一个数据表包含多个数据行,一个数据行包含多个单元格,单元格能且仅能包含一个文本块,前提是文本块是一个列文本(TextColumn)并且在只读模式下(在编辑模式下会变为文本框(TextBox))。在树形结构下,表的结构有点复杂:  

需要注意的是,数据列不是树形结构的一部分。但是对数据列做出的任何定义将会被应用至那一列的所有单元格。

WPF 捆绑基础

捆绑将会被分配至一个FrameworkElement属性,由这个属性组成要捆绑的目标容器。

WPF捆绑需要2个参数:  

来源: 哪个对象提供了信息?

路径: 对象下的哪个属性可以使用 ?

通常情况下,来源继承自它自己父容器的数据文本(DataContext)属性。但是数据表格的此属性无法被用于捆绑行和单元格,因为每一行都需要捆绑不同的业务逻辑对象。

数据列将指定的捆绑数据呈现在每个单元格中,与对应的属性捆绑。在运行时,数据表会为每一个文本块的文本(TextBlock.Text)创建一个捆绑。不幸的是,并不是所有属性的文本块都支持被数据表捆绑。如果你想自定义文本块的格式,那么你很有可能会失败,因为捆绑操作并不知道你使用的是目标资源中的哪个业务对象。

提取业务数据

通过下面的方法获取数据:

public class StockItem {
  public string Name { get; set; }
  public int Quantity { get; set; }
  public bool IsObsolete { get; set; }
} 

例: 

Name Quantity   IsObsolete  
Many items  100 false
Enough items 10 false
Shortage item 1 false
Item with error   -1 false
Obsolete item 200 true 

在数据表和业务数据之间建立连接

难点并不在于数据表和业务数据之间连接的建立,通常我们可以用CollectionViewSource来建立此种连接。 

CollectionViewSource完成导航、排序、筛选等事项。

1) 在Windows.Resource中定义CollectionViewSource

<Window.Resources>
    <CollectionViewSource x:Key="ItemCollectionViewSource"  CollectionViewType="ListCollectionView"/>
</Window.Resources>   

关键在于,这里你必须使用CollectionViewType。否则数据表将使用 BindingListCollectionView,而这个空间将不具备排序功能。当然,MSDN并没有在任何地方提及这个事情。

2) 设置数据表的DataContext属性和 CollectionViewSource建立连接关系。

<DataGrid
  DataContext="{StaticResource ItemCollectionViewSource}"
  ItemsSource="{Binding}"
  AutoGenerateColumns="False"
  CanUserAddRows="False">  
3) 在下面的代码中,找到CollectionViewSource,并将业务数据指定为来源属性。
//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; 
本文中的数据权限仅为可读。如果想让用户可以修改数据,可以使用ObservableCollection。

构建数据表 

构建列

如果仅是对整个列进行调整,只需设置数据列(DataGridColumn)中的某个属性就好了,比如字体加粗:

<DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" FontWeight="Bold"/>
目前为止的数据捆绑还未涉及到表格的创建,仅是对内容进行编辑(例如文本块中的文本属性)。

构建所有的行

构建行的方法比较特殊,因为涉及到很多行,所以数据表提供了RowStyle属性。对此属性进行操作将会涉及到所有的行。

<datagrid.rowstyle>
  <style targettype="DataGridRow">
    <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self},
      Path=Item.Quantity, Converter={StaticResource QuantityToBackgroundConverter}}"/>
  </style>
</datagrid.rowstyle>

DatGridRow 有一个 包含该行的业务逻辑对象的 Item 属性,因此 DataRow 的绑定必须绑定到它自己!有点奇怪的是 Path,因为 Item 是类型对象并且不知道任何的业务数据属性。但 WPF 绑定应用了一点魔力,无论怎样都能查找 Stock 项目的 Quantity 属性。

在这个例子中,背景(background)这一行依赖于业务对象的 Quantity 属性的值。在 stock 中如果有许多项,背景应该是白色的,如果只剩下几个,背景应该是灰色的。QuantityToBackgroundConverter 完成了必要的计算:

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();
   }
}  

格式化一个基于所显示的值的单元格

仅格式化一个单元格而不是整行是一个挑战。在文本列中,单元格有一个需要样式的 TextBlock。为 TextBlock 创建一个样式是简单的,但如何将 TextBlock 属性限制在适当的业务对象上呢?DataGrit 已经绑定到 TextBlock 的 Text 属性了。如果样式仅依赖与单元格的值,我们可以简单地对这个 Text 属性使用一个自我约束 。

例如:在我们的 stock 网格中,Quantity 应该一直大于或等于零。如果某个 quantity 是不符的,那么它将以红色显示一个错误:

<Setter Property="Foreground" 
  Value="{Binding 
    RelativeSource={RelativeSource Self}, 
    Path=Text, 
    Converter={StaticResource QuantityToForegroundConverter}}" /> 

格式化一个基于业务逻辑数据的单元格

最复杂的情况是如果单元格格式不是依赖于单元格的值,而是其他的一些业务数据。在我们的例子中,Quantity 中的某一项如果是丢弃的就应该显示为完全穿透。 为了达到这个目的,TextDecorations 属性需要链接到那一行的业务对象。这意味着 TextBlock 不得不查找父级的 DataGridRow。幸运的是,可以使用一个相对源绑定到一个父级可视对象:

<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();
  }
}

代码

请在 Zip 文件中查看样例的完整源代码。

 代码(Zip 文件) 

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。 2KB翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。


2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务

  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【计算机/互联网|】Nginx出现502错误(2020-01-20 21:02)
【计算机/互联网|】网站运营全智能软手V0.1版发布(2020-01-20 12:16)
【计算机/互联网|】淘宝这是怎么了?(2020-01-19 19:15)
【行业动态|】谷歌关闭小米智能摄像头,因为窃听器显示了陌生人家中的照片(2020-01-15 09:42)
【行业动态|】据报道谷歌新闻终止了数字杂志,退还主动订阅(2020-01-15 09:39)
【行业动态|】康佳将OLED电视带到美国与LG和索尼竞争(2020-01-15 09:38)
【行业动态|】2020年最佳AV接收机(2020-01-15 09:35)
【行业动态|】2020年最佳流媒体设备:Roku,Apple TV,Firebar,Chromecast等(2020-01-15 09:31)
【行业动态|】CES 2020预览:更多的流媒体服务和订阅即将到来(2020-01-08 21:41)
【行业动态|】从埃隆·马斯克到杰夫·贝佐斯,这30位人物定义了2010年代(2020-01-01 15:14)
联系我们

Q Q: 7090832

电话:400-0011-990

邮箱:7090832@qq.com

时间:9:00-23:00

联系客服
商家入住 服务咨询 投拆建议 联系客服
0577-67068160
手机版

扫一扫进手机版
返回顶部