NPOI導出WPF DataGrid控制項顯示數據

来源:http://www.cnblogs.com/ZXdeveloper/archive/2017/10/14/7667416.html
-Advertisement-
Play Games

最近做個項目,需要導出DataGrid顯示的數據,中間遇到了不少的坑,在此紀錄一下,方便以後查看,也希望能給用到的人,一點幫助。 導出DataGrid顯示的數據,並不是導出DataGrid的ItemsSource,這兩者是有區別的,這裡紀錄的是導出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源碼


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 當程式在測試或者老化的時候很有用,只要程式有異常拋出,就能啟用windbg調試,這樣就能及時的保存現場。 程式崩潰時,windows系統會調用系統預設調試器,其設置在註冊表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion ...
  • 本文目錄:1 編譯nginx2 編譯php3 配置nginx和php-fpm交互 1. 編譯nginx rpm包格式的nginx地址:http://nginx.org/packages/源碼包下載地址:http://nginx.org/en/download.html 。本文下載的是最新穩定版ngi ...
  • 一、apache、php、mysql安裝 安裝順序:apache/mysql 最後安裝php 前兩者順序無所謂。 1.安裝apache 需要伺服器聯網 安裝:yum install -y httpd 運行:/bin/systemctl start httpd.service 執行完運行命令之後是看不 ...
  • 新增與移除使用者: useradd, 相關配置文件, passwd, usermod, userdel 我們登入系統時會輸入 (1)賬號與 (2)密碼,所以建立一個可用的賬號同樣的也需要這兩個數據。那賬號可以使用 useradd 來新建用戶, 密碼的給予則使用 passwd 這個指令!這兩個指令下達 ...
  • aspx類的驗證碼處理程式,隨後還會記錄一般程式的的驗證碼類 1 using System; 2 using System.Collections.Generic; 3 using System.Web; 4 using System.Web.UI; 5 using System.Web.UI.We ...
  • - 我們在做http請求的時候如果想讓返回的格式以json字元串返回: httpClient.DefaultRequestHeaders.Add("Accept","application/json;odata=verbose"); HttpClient中有有參構造函數,其中的有參構造函數包括有參數 ...
  • 似乎...很久很久沒有寫博客了,一直都想寫兩篇,但是卻沒有時間寫。感覺最近有很多事情需要處理,一直都是疲於奔命,一直到最近才變得有些時間學習和充電。最近沒有事情都會看一些博客和開源項目,發現介紹開源項目的文章似乎有些舊,而且很多介紹開源項目的文章都有比較相似的地方,畢竟.NET很好很實用的項目的確有 ...
  • 簡單的程式總結 一個簡單的用於控制LED屏幕的小程式,用到的一個常識 LED服務開發總結 系統運行截圖 系統功能說明: 1、ServerStrack服務,提供前臺訪問。 2、動態庫調用,用於信息轉發。 3、rest服務調用,用於更新後臺數據。 4、資料庫技術,用於數據維護。 詳細知識點 1、C++動 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...