最近做个项目,需要导出DataGrid显示的数据,中间遇到了不少的坑,在此纪录一下,方便以后查看,也希望能给用到的人,一点帮助。

导出DataGrid显示的数据,并不是导出DataGrid的ItemsSource,这两者是有区别的,这里纪录的是导出DataGrid的显示数据,也就是所见即所得的东西。

举个例子:

我这里有个一个People的实体类,它包含了6个字段,如下

public class People
{
public string Name { get; set; }
public int Age { get; set; }
public int Sex { get; set; }
public string ClassName { get; set; }
public string GradeName { get; set; }
public string SchoolName { get; set; }
}

然而,将List<People>的集合给DataGrid的ItemsSource进行赋值,但是我页面,显示的是5个字段,甚至还有一个转换器的使用

<DataGrid x:Name="dg_x" CanUserAddRows="False" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="姓名" Binding="{Binding Name}" Width="*" />
<DataGridTextColumn Header="年龄" Binding="{Binding Age}" Width="*" />
<DataGridTextColumn Header="性别" Binding="{Binding Sex,Converter={StaticResource sexcov}}" Width="*" />
<DataGridTextColumn Header="年级" Binding="{Binding GradeName}" Width="*" />
<DataGridTextColumn Header="学校" Binding="{Binding SchoolName}" Width="*" />
</DataGrid.Columns>
</DataGrid>

导出的效果就是DataGrid上展示的数据,加了少许的样式

接下来,我们介绍下我在写代码过程中遇到的两个坑

一、代码顺序问题

做到上面的内容大致需要做两个工作,第一个就是要取得到DataGrid的Cell的值,基本上百度一下,就会看到一个方法,好多的博客都有,如下

http://www.cnblogs.com/qq247039968/p/4066058.html

这个方法本身是没啥问题,但是,当DataGrid有滚动条的时候,也就是DataGrid的Row没有完全渲染完的情况就有问题了。

假设,我现在有30条数据,但是,我没有拖动过滚动条,直接点导出的话,会抛出如下的异常:

看了下代码,是因为presenter这是Null,继续打断点跟踪,发现此处numVisuals得到的值是0,而不是1,也就是说没有获取到内容,所以返回的Null。

出现以上问题的原因,在于,以下代码的一个顺序问题

大家都知道UpdateLayout函数是更新布局的意思,这两段代码,是先更新了布局,然后,滚动到rowIndex的位置,所以,依然没有渲染成功。

正确的写法是将两句的顺序换一下位置,先滚动,再更新,就不会出现问题了。

public static class DataGridPlus
{
/// <summary>
/// 获取DataGrid的行
/// </summary>
/// <param name="dataGrid">DataGrid控件</param>
/// <param name="rowIndex">DataGrid行号</param>
/// <returns>指定的行号</returns>
public static DataGridRow GetRow(this DataGrid dataGrid, int rowIndex)
{ DataGridRow rowContainer = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex);
if (rowContainer == null)
{
dataGrid.ScrollIntoView(dataGrid.Items[rowIndex]);
dataGrid.UpdateLayout();
rowContainer = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex);
}
return rowContainer;
}
/// <summary>
/// 获取父可视对象中第一个指定类型的子可视对象
/// </summary>
/// <typeparam name="T">可视对象类型</typeparam>
/// <param name="parent">父可视对象</param>
/// <returns>第一个指定类型的子可视对象</returns>
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T); int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = ; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
/// <summary>
/// 获取DataGrid控件单元格
/// </summary>
/// <param name="dataGrid">DataGrid控件</param>
/// <param name="rowIndex">单元格所在的行号</param>
/// <param name="columnIndex">单元格所在的列号</param>
/// <returns>指定的单元格</returns>
public static DataGridCell GetCell(this DataGrid dataGrid, int rowIndex, int columnIndex)
{
DataGridRow rowContainer = dataGrid.GetRow(rowIndex);
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
if (cell == null)
{
dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[columnIndex]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
}
return cell;
}
return null;
}
}

DataGridPlus

点击导出之后,滚动条会自动滚到DataGrid的结尾处

二、过多的创建了样式和字体

NPOI的Style是针对单元格的,所以,如果导出上面一个最普通的表格的话,就要至少9个样式,这个不在于Font的字体或者怎么样,而是在于Border

粗和细的问题,基本上一个表格,最外面的框的粗线,内部是细线。

由于,第一次用NPOI,以前没用过,所以,在设置样式是,给放在了for里面,当时的想法,就是判断下处于列的什么位置,或者是处于行的什么位置,来设置Cell的样式

但是,数量少的时候是没问题的,当数量多了以后,由于不断的New,导致,会提示Style的数量抄了,当时好像大概测试了2W条数据吧。

因此,需要将所有的样式,都提出来,在最前面定义好,需要的时候,直接赋值就好了。

位置的话,通过枚举来定义,方便使用

public enum CellPosition
{
LeftTop,
Top,
RightTop,
Left,
Center,
Right,
LeftBottom,
Bottom,
RightBottom,
None
}

还要注意的是NPOI可以通过DefaultColumnWidth来设置默认的宽度,但是DefaultRowHeight和DefaultRowHeightInPoints设置默认高度却不好使,我看作者在13年的时候已经修复这个问题了,但是不知道为什么还是不起左右,有知道的,希望可以留言告知,谢谢。

DEMO源码

NPOI导出WPF DataGrid控件显示数据的更多相关文章

  1. WPF DataGrid 控件的运用

    WPF DataGrid 控件的运用 运行环境:Window7 64bit,.NetFramework4.61,C# 6.0: 编者:乌龙哈里 2017-02-23 参考: King Cobra 博客 ...

  2. C# WPF DataGrid控件实现三级联动

    利用DataGrid控件实现联动的功能,在数据库客户软件中是随处可见的,然而网上的资料却是少之又少,令人崩溃. 本篇博文将介绍利用DataGrid控件模板定义的三个ComboBox实现“省.市.区”的 ...

  3. Delphi7连接MySql数据库-DBGrid控件显示数据

    一个简单的Delphi7小程序,使用MySql数据库做简单查询,用DBGrid控件显示结果,实现过程如下: (1)在MySql中新建demouser表,插入记录用于测试. (2)在Delphi7中新建 ...

  4. WPF DataGrid控件中某一列根据另一个文本列的值显示相应的模板控件

    之前做项目的时候需要实现这样一个功能.WPF DataGrid有两列,一列为"更新状态”列,一列为"值"列,如果"更新状态"列的值为“固定值更新”,则 ...

  5. 使用Listview控件显示数据

    1.图像列表控件 ImageList是含有图像对象的集合,可以通过索引或关键字引用该集合中的每个对象. ImageList空间的属性 属性 说明 Images 存储在图像列表中的所有图像 ImageS ...

  6. C# 解决ListView控件显示数据出现闪屏的问题

    一.发现问题 如果发送数据过快的情况下,ListVies滚屏显示数据时会显示闪屏,如下所示现象: 二.解决问题 根据出现闪屏的情况,在网上查了资料要使用双缓存的办法来处理.其原理是数据在缓存区中进行处 ...

  7. asp.net LINQ LinqDataSource控件显示数据和DropdownList显示数据

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.We ...

  8. ADO.NET之使用DataGridView控件显示从服务器上获取的数据

    今天回顾下ADO.NET中关于使用DataGridiew控件显示数据的相关知识 理论整理: 使用 DataGridView 控件,可以显示和编辑来自多种不同类型的数据源的表格数据. SqlDataAd ...

  9. WPF:获取DataGrid控件单元格DataGridCell

    转载:http://blog.csdn.net/jhqin/article/details/7645357 /* ------------------------------------------- ...

随机推荐

  1. 原生的AJAX

    var XHR=null; if (window.XMLHttpRequest) { // 非IE内核 XHR = new XMLHttpRequest(); } else if (window.Ac ...

  2. MongoDB学习之路(四)

    MongoDB插入文档 MongoDB使用insert()或save()方法向集合中插入文档. db.COLLECTION_NAME.insert(document); For instance &g ...

  3. 四则运算GUI

    一.题目描述 我们在个人作业1中,用各种语言实现了一个命令行的四则运算小程序.进一步,本次要求把这个程序做成GUI(可以是Windows PC 上的,也可以是Mac.Linux,web,手机上的),成 ...

  4. 201521123121 《JAVA程序设计》第8周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声 ...

  5. 学号:201521123116 《java程序设计》第七周学习总结

    1. 本周学习总结 2. 书面作业 Q1 ArrayList代码分析 1.1 解释ArrayList的contains源代码ArrayList的contains源代码 1.2 解释E remove(i ...

  6. 201521123029《Java程序设计》第五周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 答:1. 课上讲了匿名内部类的使用,其中内部类就是定义在另一个类里面的类,与之相 ...

  7. python学习笔记1.2

    在python中%的用处是求余数,而不是除数.

  8. 201521123109 《java程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  9. PHP面向对象简单总结

    类和对象对象:一切东西都可以看做对象,对象是类的实例化.类:类是对象的抽象,用来描述众多对象共有的特征. 定义类 class成员变量 和 成员方法访问修饰符 public共有的 private 私有的 ...

  10. Mybatis第二篇【CRUD、分页】

    完成CRUD操作 我们在上一篇中已经简单知道了Mybatis是怎么使用的以及工作流程了,这次我们使用Mybatis来完成CRUD的操作,再次巩固Mybatis的开发步骤以及一些细节 包与类之间的结构 ...