65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF DataGrid 的导出到 Excel 功能

starIconstarIconstarIconstarIconstarIcon

5.00/5 (15投票s)

2010年10月22日

CPOL

3分钟阅读

viewsIcon

150896

downloadIcon

7102

本文介绍了从 WPF datagrid 导出 Excel 表格的功能。

引言

开发人员经常收到业务用户的需求,要求将任何集合项(listviewgridviewlistbox)中的数据导出,以便在应用程序未运行时,他们可以根据自己的需要使用这些数据。为此,开发人员通常将数据导出为 PDF、Word、Excel 和 RTF 格式。DataGrid 控件是在 WPFToolkit 中引入的,可以与 VS 2008 一起使用。目前,Visual Studio 2010 本身就捆绑了它。在本文中,我们将探讨如何从 datagrid 创建 Excel 文件。我们将尝试以一种非常简单的方式来解释这个概念。开发人员可以根据需要进行更改。

将 WPF DataGrid 导出到 Microsoft Excel

步骤 1

打开一个 Visual Studio 2008 实例。确保您的机器上安装了 WPF Toolkit。如果没有,请从这个链接下载。请务必添加 WPFToolkit 的引用。

步骤 2

创建一个 WPF 屏幕,如代码片段 XAML 文件所示

<Window x:Class="ExportToExcel.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:toolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
    xmlns:local="clr-namespace:ExportToExcel"
    Title="DataGrid Excel Export" Height="400" Width="250">   
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="150"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="150"/>
        </Grid.RowDefinitions>
        <Button Grid.Row="0" HorizontalAlignment="Right" Width="50" 
		Height="25" Content="Export" Click="btnEmployee_Click" 

Name="btnEmployee"/>
        <toolkit:DataGrid Grid.Row="1" Name="dgEmployee" 
		SelectionMode="Single" AutoGenerateColumns="False" IsReadOnly="True" 

Margin="5,5,5,5">
            <toolkit:DataGrid.Columns>
                <toolkit:DataGridTextColumn Binding="{Binding Path=Id}" 
		Header="Id" Width="45"/>
                <toolkit:DataGridTextColumn Binding="{Binding Path=Name}" 
		Header="Name" Width="100"/>
                <toolkit:DataGridTextColumn Binding="{Binding Path=Designation}" 
		Header="Designation" Width="*"/>                
            </toolkit:DataGrid.Columns>
        </toolkit:DataGrid>

        <Button Grid.Row="2" HorizontalAlignment="Right" Width="50" 
		Height="25" Content="Export" Click="btnBook_Click" 

Name="btnBook"/>
        <toolkit:DataGrid Grid.Row="3" Name="dgBook" 
	SelectionMode="Single" AutoGenerateColumns="False" IsReadOnly="True" 

Margin="5,5,5,5">
            <toolkit:DataGrid.Columns>
                <toolkit:DataGridTextColumn Binding="{Binding Path=ISBN}" 
		Header="ISBN" Width="45"/>
                <toolkit:DataGridTextColumn Binding="{Binding Path=Title}" 
		Header="Title" Width="100"/>
                <toolkit:DataGridTextColumn Binding="{Binding Path=Author}" 
		Header="Author" Width="*"/>
                
            </toolkit:DataGrid.Columns>
        </toolkit:DataGrid>
    </Grid>
</Window>

步骤 3

屏幕将如下所示

UIScreenDev.JPG

步骤 4

我们将把两个不同的类绑定到两个 datagrid。第一个 datagrid 与类 Employees 绑定,第二个与 Books 绑定。

/// <summary>
/// List of Employee Class 
/// </summary>
public class Employees : List<employee> { }
/// <summary>
/// Employee Class
/// </summary>
public class Employee
{
    private int id;
    
    public int Id
    {
        get { return id; }
        set { id = value; }
    }
    private string name;
    
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
    private string designation;
    
    public string Designation
    {
        get { return designation; }
        set { designation = value; }
    }
}

/// <summary>
/// List of Book class
/// </summary>
public class Books : List<book> { }

/// <summary>
/// Book Class
/// </summary>
public class Book
{
    private int iSBN;
     
    public int ISBN
    {
        get { return iSBN; }
        set { iSBN = value; }
    }
    private string title;
    
    public string Title
    {
        get { return title; }
        set { title = value; }
    }
    private string author;
    
    public string Author
    {
        get { return author; }
        set { author = value; }
    }
}

步骤 5

向类中添加一些数据,并将它们绑定到 datagrid

public Window1()
{
            InitializeComponent();
            Employees emps = new Employees();

            Employee e1 = new Employee();
            e1.Id = 52590;
            e1.Name = "Sathish";
            e1.Designation = "Developer";            
            emps.Add(e1);

            Employee e2 = new Employee();
            e2.Id = 52592;
            e2.Name = "Karthick";
            e2.Designation = "Developer";            
            emps.Add(e2);

            Employee e3 = new Employee();
            e3.Id = 52593;
            e3.Name = "Raja";
            e3.Designation = "Manager";            
            emps.Add(e3);

            Employee e4 = new Employee();
            e4.Id = 12778;
            e4.Name = "Sumesh";
            e4.Designation = "Project Lead";            
            emps.Add(e4);

            Employee e5 = new Employee();
            e5.Id = 12590;
            e5.Name = "Srini";
            e5.Designation = "Project Lead";            
            emps.Add(e5);
            
            dgEmployee.ItemsSource = emps;

            Books books = new Books();

            Book b1 = new Book();
            b1.ISBN = 582912;
            b1.Title = "C#";
            b1.Author = "James";
            books.Add(b1);

            Book b2 = new Book();
            b2.ISBN = 174290;
            b2.Title = "WPF";
            b2.Author = "Smith";
            books.Add(b2);

            Book b3 = new Book();
            b3.ISBN = 095177;
            b3.Title = ".NET";
            b3.Author = "Robert";
            books.Add(b3);

            Book b4 = new Book();
            b4.ISBN = 112275;
            b4.Title = "Java";
            b4.Author = "Steve";
            books.Add(b4);

            Book b5 = new Book();
            b5.ISBN = 998721;
            b5.Title = "COBOL";
            b5.Author = "John";
            books.Add(b5);

            dgBook.ItemsSource = books;
} 

步骤 6

导出到 Excel 的操作可以从下面的流程图中理解

Flow.JPG

步骤 7

现在我们将探讨代码。

/// <summary>
/// Class for generator of Excel file
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
public class ExportToExcel<T, U>
    where T : class
    where U : List<T>
{
    public List<T> dataToPrint;
    // Excel object references.
    private Excel.Application _excelApp = null;
    private Excel.Workbooks _books = null;
    private Excel._Workbook _book = null;
    private Excel.Sheets _sheets = null;
    private Excel._Worksheet _sheet = null;
    private Excel.Range _range = null;
    private Excel.Font _font = null;
    // Optional argument variable
    private object _optionalValue = Missing.Value;
    
    /// <summary>
    /// Generate report and sub functions
    /// </summary>
    public void GenerateReport()
    {
        try
        {
            if (dataToPrint != null)
            {
                if (dataToPrint.Count != 0)
                {
                    Mouse.SetCursor(Cursors.Wait);
                    CreateExcelRef();
                    FillSheet();
                    OpenReport();
                    Mouse.SetCursor(Cursors.Arrow);
                }
            }
        }
        catch (Exception e)
        {
            MessageBox.Show("Error while generating Excel report");
        }
        finally
        {
            ReleaseObject(_sheet);
            ReleaseObject(_sheets);
            ReleaseObject(_book);
            ReleaseObject(_books);
            ReleaseObject(_excelApp);
        }
    }
    /// <summary>
    /// Make Microsoft Excel application visible
    /// </summary>
    private void OpenReport()
    {
        _excelApp.Visible = true;
    }
    /// <summary>
    /// Populate the Excel sheet
    /// </summary>
    private void FillSheet()
    {
        object[] header = CreateHeader();
        WriteData(header);
    }
    /// <summary>
    /// Write data into the Excel sheet
    /// </summary>
    /// <param name="header"></param>
    private void WriteData(object[] header)
    {
        object[,] objData = new object[dataToPrint.Count, header.Length];
        
        for (int j = 0; j < dataToPrint.Count; j++)
        {
            var item = dataToPrint[j];
            for (int i = 0; i < header.Length; i++)
            {
                var y = typeof(T).InvokeMember
		(header[i].ToString(), BindingFlags.GetProperty, null, item, null);
                objData[j, i] = (y == null) ? "" : y.ToString();
            }
        }
        AddExcelRows("A2", dataToPrint.Count, header.Length, objData);
        AutoFitColumns("A1", dataToPrint.Count + 1, header.Length);
    }
    /// <summary>
    /// Method to make columns auto fit according to data
    /// </summary>
    /// <param name="startRange"></param>
    /// <param name="rowCount"></param>
    /// <param name="colCount"></param>
    private void AutoFitColumns(string startRange, int rowCount, int colCount)
    {
        _range = _sheet.get_Range(startRange, _optionalValue);
        _range = _range.get_Resize(rowCount, colCount);
        _range.Columns.AutoFit();
    }
    /// <summary>
    /// Create header from the properties
    /// </summary>
    /// <returns></returns>
    private object[] CreateHeader()
    {
        PropertyInfo[] headerInfo = typeof(T).GetProperties();
        
        // Create an array for the headers and add it to the
        // worksheet starting at cell A1.
        List<object> objHeaders = new List<object>();
        for (int n = 0; n < headerInfo.Length; n++)
        {
            objHeaders.Add(headerInfo[n].Name);
        }
        
        var headerToAdd = objHeaders.ToArray();
        AddExcelRows("A1", 1, headerToAdd.Length, headerToAdd);
        SetHeaderStyle();
        
        return headerToAdd;
    }
    /// <summary>
    /// Set Header style as bold
    /// </summary>
    private void SetHeaderStyle()
    {
        _font = _range.Font;
        _font.Bold = true;
    }
    /// <summary>
    /// Method to add an excel rows
    /// </summary>
    /// <param name="startRange"></param>
    /// <param name="rowCount"></param>
    /// <param name="colCount"></param>
    /// <param name="values"></param>
    private void AddExcelRows
	(string startRange, int rowCount, int colCount, object values)
    {
        _range = _sheet.get_Range(startRange, _optionalValue);
        _range = _range.get_Resize(rowCount, colCount);
        _range.set_Value(_optionalValue, values);
    }       
    /// <summary>
    /// Create Excel application parameters instances
    /// </summary>
    private void CreateExcelRef()
    {
        _excelApp = new Excel.Application();
        _books = (Excel.Workbooks)_excelApp.Workbooks;
        _book = (Excel._Workbook)(_books.Add(_optionalValue));
        _sheets = (Excel.Sheets)_book.Worksheets;
        _sheet = (Excel._Worksheet)(_sheets.get_Item(1));
    }
    /// <summary>
    /// Release unused COM objects
    /// </summary>
    /// <param name="obj"></param>
    private void ReleaseObject(object obj)
    {
        try
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
            obj = null;
        }
        catch (Exception ex)
        {
            obj = null;
            MessageBox.Show(ex.Message.ToString());
        }
        finally
        {
            GC.Collect();
        }
    }
}

强制类 ExportToExcel 获取两个参数,TUT 参数应该是类,U 应该是 T 对象的列表。这是为了确保该类获得正确的输入。此外,对于 datagrid,我们通常绑定一个对象列表。GenerateReport 方法将创建/初始化 Excel 应用程序,填充 Excel 列和行。

大多数代码是不言自明的,其中 CreateHeaderWriteData 方法更加重要。CreateHeader 使用反射来获取我们传递的类的属性。从这些数据中,我们将在 Excel 表格中打印列标题。WriteData 方法知道有多少列(来自 CreateHeader 方法)和总数据(来自 dataToPrint.Count)。形成一个二维数组,并使用反射填充该数组。生成的二维数组被填充到 Excel 表格中。

步骤 8

当我们运行代码时,WPF 窗体将显示给用户。

Output.JPG

当我们按下 booksEmployee datagrid 的“导出”按钮,并使用以下代码时:

/// <summary>
/// Event for generating excel sheet for books datagrid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnBook_Click(object sender, RoutedEventArgs e)
{
    ExportToExcel<Book, Books> s = new ExportToExcel<Book, Books>();            
    ICollectionView view = CollectionViewSource.GetDefaultView(dgBook.ItemsSource);    
    s.dataToPrint = (Books)view.SourceCollection;
    s.GenerateReport();
}
/// <summary>
/// Event for generating excel sheet for employee datagrid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnEmployee_Click(object sender, RoutedEventArgs e)
{
    ExportToExcel<Employee, Employees> s = new ExportToExcel<Employee, Employees>();
    s.dataToPrint = (Employees)dgEmployee.ItemsSource;
    s.GenerateReport();
}

我们将获得一个包含数据的 Excel 文件,如下面 Book 的截图所示

BookOutput.JPG

以及下面 Employee 按钮的截图

EmployeeOutput.JPG

完整的代码列表如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
using tool = Microsoft.Windows.Controls;
using System.ComponentModel;

namespace ExportToExcel
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            Employees emps = new Employees();

            Employee e1 = new Employee();
            e1.Id = 52590;
            e1.Name = "Sathish";
            e1.Designation = "Developer";            
            emps.Add(e1);

            Employee e2 = new Employee();
            e2.Id = 52592;
            e2.Name = "Karthick";
            e2.Designation = "Developer";            
            emps.Add(e2);

            Employee e3 = new Employee();
            e3.Id = 52593;
            e3.Name = "Raja";
            e3.Designation = "Manager";            
            emps.Add(e3);

            Employee e4 = new Employee();
            e4.Id = 12778;
            e4.Name = "Sumesh";
            e4.Designation = "Project Lead";            
            emps.Add(e4);

            Employee e5 = new Employee();
            e5.Id = 12590;
            e5.Name = "Srini";
            e5.Designation = "Project Lead";            
            emps.Add(e5);
            
            dgEmployee.ItemsSource = emps;

            Books books = new Books();

            Book b1 = new Book();
            b1.ISBN = 582912;
            b1.Title = "C#";
            b1.Author = "James";
            books.Add(b1);

            Book b2 = new Book();
            b2.ISBN = 174290;
            b2.Title = "WPF";
            b2.Author = "Smith";
            books.Add(b2);

            Book b3 = new Book();
            b3.ISBN = 095177;
            b3.Title = ".NET";
            b3.Author = "Robert";
            books.Add(b3);

            Book b4 = new Book();
            b4.ISBN = 112275;
            b4.Title = "Java";
            b4.Author = "Steve";
            books.Add(b4);

            Book b5 = new Book();
            b5.ISBN = 998721;
            b5.Title = "COBOL";
            b5.Author = "John";
            books.Add(b5);

            dgBook.ItemsSource = books;
        }         
        /// <summary>
        /// Event for generating excel sheet for books datagrid
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnBook_Click(object sender, RoutedEventArgs e)
        {
            ExportToExcel<Book, Books> s = new ExportToExcel<Book, Books>();            
            ICollectionView view = 
		CollectionViewSource.GetDefaultView(dgBook.ItemsSource);            
            s.dataToPrint = (Books)view.SourceCollection;
            s.GenerateReport();
        }
        /// <summary>
        /// Event for generating excel sheet for employee datagrid
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnEmployee_Click(object sender, RoutedEventArgs e)
        {
            ExportToExcel<Employee, Employees> s = 
			new ExportToExcel<Employee, Employees>();
            s.dataToPrint = (Employees)dgEmployee.ItemsSource;
            s.GenerateReport();
        }
    }
    
    /// <summary>
    /// Class for generator of Excel file
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="U"></typeparam>
    public class ExportToExcel<T, U>
        where T : class
        where U : List<T>
    {
        public List<T> dataToPrint;
        // Excel object references.
        private Excel.Application _excelApp = null;
        private Excel.Workbooks _books = null;
        private Excel._Workbook _book = null;
        private Excel.Sheets _sheets = null;
        private Excel._Worksheet _sheet = null;
        private Excel.Range _range = null;
        private Excel.Font _font = null;
        // Optional argument variable
        private object _optionalValue = Missing.Value;

        /// <summary>
        /// Generate report and sub functions
        /// </summary>
        public void GenerateReport()
        {
            try
            {
                if (dataToPrint != null)
                {
                    if (dataToPrint.Count != 0)
                    {
                        Mouse.SetCursor(Cursors.Wait);
                        CreateExcelRef();
                        FillSheet();
                        OpenReport();
                        Mouse.SetCursor(Cursors.Arrow);
                    }
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Error while generating Excel report");
            }
            finally
            {
                ReleaseObject(_sheet);
                ReleaseObject(_sheets);
                ReleaseObject(_book);
                ReleaseObject(_books);
                ReleaseObject(_excelApp);
            }
        }
        /// <summary>
        /// Make MS Excel application visible
        /// </summary>
        private void OpenReport()
        {
            _excelApp.Visible = true;
        }
        /// <summary>
        /// Populate the Excel sheet
        /// </summary>
        private void FillSheet()
        {
            object[] header = CreateHeader();
            WriteData(header);
        }
        /// <summary>
        /// Write data into the Excel sheet
        /// </summary>
        /// <param name="header"></param>
        private void WriteData(object[] header)
        {
            object[,] objData = new object[dataToPrint.Count, header.Length];

            for (int j = 0; j < dataToPrint.Count; j++)
            {
                var item = dataToPrint[j];
                for (int i = 0; i < header.Length; i++)
                {
                    var y = typeof(T).InvokeMember(header[i].ToString(), 
                    BindingFlags.GetProperty, null, item, null);
                    objData[j, i] = (y == null) ? "" : y.ToString();
                }
            }
            AddExcelRows("A2", dataToPrint.Count, header.Length, objData);
            AutoFitColumns("A1", dataToPrint.Count + 1, header.Length);
        }
        /// <summary>
        /// Method to make columns auto fit according to data
        /// </summary>
        /// <param name="startRange"></param>
        /// <param name="rowCount"></param>
        /// <param name="colCount"></param>
        private void AutoFitColumns(string startRange, int rowCount, int colCount)
        {
            _range = _sheet.get_Range(startRange, _optionalValue);
            _range = _range.get_Resize(rowCount, colCount);
            _range.Columns.AutoFit();
        }
        /// <summary>
        /// Create header from the properties
        /// </summary>
        /// <returns></returns>
        private object[] CreateHeader()
        {
            PropertyInfo[] headerInfo = typeof(T).GetProperties();

            // Create an array for the headers and add it to the
            // worksheet starting at cell A1.
            List<object> objHeaders = new List<object>();
            for (int n = 0; n < headerInfo.Length; n++)
            {
                objHeaders.Add(headerInfo[n].Name);
            }

            var headerToAdd = objHeaders.ToArray();
            AddExcelRows("A1", 1, headerToAdd.Length, headerToAdd);
            SetHeaderStyle();

            return headerToAdd;
        }
        /// <summary>
        /// Set Header style as bold
        /// </summary>
        private void SetHeaderStyle()
        {
            _font = _range.Font;
            _font.Bold = true;
        }
        /// <summary>
        /// Method to add an excel rows
        /// </summary>
        /// <param name="startRange"></param>
        /// <param name="rowCount"></param>
        /// <param name="colCount"></param>
        /// <param name="values"></param>
        private void AddExcelRows(string startRange, int rowCount, 
		int colCount, object values)
        {
            _range = _sheet.get_Range(startRange, _optionalValue);
            _range = _range.get_Resize(rowCount, colCount);
            _range.set_Value(_optionalValue, values);
        }       
        /// <summary>
        /// Create Excel application parameters instances
        /// </summary>
        private void CreateExcelRef()
        {
            _excelApp = new Excel.Application();
            _books = (Excel.Workbooks)_excelApp.Workbooks;
            _book = (Excel._Workbook)(_books.Add(_optionalValue));
            _sheets = (Excel.Sheets)_book.Worksheets;
            _sheet = (Excel._Worksheet)(_sheets.get_Item(1));
        }
        /// <summary>
        /// Release unused COM objects
        /// </summary>
        /// <param name="obj"></param>
        private void ReleaseObject(object obj)
        {
            try
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
                obj = null;
            }
            catch (Exception ex)
            {
                obj = null;
                MessageBox.Show(ex.Message.ToString());
            }
            finally
            {
                GC.Collect();
            }
        }
    }

    /// <summary>
    /// List of Employee Class 
    /// </summary>
    public class Employees : List<Employee> { }
    /// <summary>
    /// Employee Class
    /// </summary>
    public class Employee
    {
        private int id;

        public int Id
        {
            get { return id; }
            set { id = value; }
        }
        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        private string designation;

        public string Designation
        {
            get { return designation; }
            set { designation = value; }
        }

    }

    /// <summary>
    /// List of Book class
    /// </summary>
    public class Books : List<Book> { }

    /// <summary>
    /// Book Class
    /// </summary>
    public class Book
    {
        private int iSBN;

        public int ISBN
        {
            get { return iSBN; }
            set { iSBN = value; }
        }
        private string title;

        public string Title
        {
            get { return title; }
            set { title = value; }
        }
        private string author;

        public string Author
        {
            get { return author; }
            set { author = value; }
        }
    }
}

进一步改进

我们目前正在探索以下可能性

  1. 如果您移动列的顺序,生成的 Excel 表格数据将与 List 中的数据相同。我们希望按照在 DataGrid 中看到的那样打印。
  2. 如果您对列进行排序,生成的 Excel 表格数据将与 List 中的数据相同。我们希望按照在 DataGrid 中看到的那样打印。
  3. 我们正在探索要导出的动态 Datagrid(意味着用户可以添加任意数量的行,并且应该可以导出它们)。
© . All rights reserved.