C# WPF DataGrid 时间字段 显示AM PM,我想飞改成24小时格式。例如:2017/12/1 17:43:53

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# WPF DataGrid 时间字段 显示AM PM,我想飞改成24小时格式。例如:2017/12/1 17:43:53相关的知识,希望对你有一定的参考价值。

由于控件所绑定的数据源是不一定的就是表和数据库不是固定的所有无法再列中格式化,数据源是DataTable类型并且无法更换,是封装在DLL文件中的。表中不一定哪个字段是时间列,无法进行列绑定格式化,而且字段数量无法保持固定。请问怎么办?

按照你这个想法,嗯 可以重写一下DataGridColumn,自定义一个DataGridColumn类继承原生DataGridColumn,然后检测当前的数据是否可以转换成时间,是的话就相应格式化。。。 这只是一个思路 不保证可行性仅供参考 参考技术A binding path是指什么呢追问

ItemsSource 绑定的是DataTable

NPOI导出WPF DataGrid控件显示数据

最近做个项目,需要导出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 = 0; 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源码

以上是关于C# WPF DataGrid 时间字段 显示AM PM,我想飞改成24小时格式。例如:2017/12/1 17:43:53的主要内容,如果未能解决你的问题,请参考以下文章

WPF C# DataGrid 绑定到存储过程

C#,WPF怎么把txt里的内容导到DataGrid里

如何在 WPF C# 中的 DataGrid 的 TextBoxes 中获取选定的行值

c# wpf datagrid 模板列修改某个单元格,更新所选行另一个单元格的值,如何做到呢?

C# WPF datagrid checkboxcolumn 使用问题

C# WPF DataGrid获取单元格并改变背景色