Silverlight DataGrid:导出到 excel 或 csv

Posted

技术标签:

【中文标题】Silverlight DataGrid:导出到 excel 或 csv【英文标题】:Silverlight DataGrid: Export to excel or csv 【发布时间】:2010-09-23 04:34:10 【问题描述】:

有没有办法可以将我的 Silverlight DataGrid 数据导出到 excel 或 csv?

我搜索了网络,但找不到任何示例!

非常感谢

【问题讨论】:

【参考方案1】:

Silverlight 3 改变了这个问题的答案,因为它使用户能够在用户桌面上指定的位置创建文件。我修改了 DaniCE 提交的代码,为了便于阅读,将内容拆分为几种方法,并使用 Excel 应该识别的松散定义的 CSV 格式。

private void exportHistoryButton_Click(object sender, RoutedEventArgs e) 

    string data = ExportDataGrid(true, historyDataGrid);
    SaveFileDialog sfd = new SaveFileDialog()
    
    DefaultExt = "csv",
    Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*",
    FilterIndex = 1
    ;
    if (sfd.ShowDialog() == true)
    
    using (Stream stream = sfd.OpenFile())
    
        using (StreamWriter writer = new StreamWriter(stream)) 
        writer.Write(data);
        writer.Close();
        
        stream.Close();
    
    


private string FormatCSVField(string data) 
    return String.Format("\"0\"",
        data.Replace("\"", "\"\"\"")
        .Replace("\n", "")
        .Replace("\r", "")
        );


public string ExportDataGrid(bool withHeaders, DataGrid grid)

    string colPath;
    System.Reflection.PropertyInfo propInfo;
    System.Windows.Data.Binding binding;
    System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
    System.Collections.IList source = (grid.ItemsSource as System.Collections.IList);
    if (source == null)
    return "";

    List<string> headers = new List<string>();
    grid.Columns.ToList().ForEach(col => 
    if (col is DataGridBoundColumn)
        headers.Add(FormatCSVField(col.Header.ToString()));
    
    );
    strBuilder
    .Append(String.Join(",", headers.ToArray()))
    .Append("\r\n");

    foreach (Object data in source)
    
    List<string> csvRow = new List<string>();
    foreach (DataGridColumn col in grid.Columns)
    
        if (col is DataGridBoundColumn)
        
        binding = (col as DataGridBoundColumn).Binding;
        colPath = binding.Path.Path;
        propInfo = data.GetType().GetProperty(colPath);
        if (propInfo != null)
        
            csvRow.Add(FormatCSVField(propInfo.GetValue(data, null).ToString()));
        
        
    
    strBuilder
        .Append(String.Join(",", csvRow.ToArray()))
        .Append("\r\n");
    


    return strBuilder.ToString();

【讨论】:

它有一些花招;它创建一个 CSV 文件,而不是 XLS。如果一个人安装了 Excel,它会通过映射到 Excel 的扩展名来打开它。 如果您在绑定行上遇到错误,请尝试像这样进行转换: binding = (System.Windows.Data.Binding)((Microsoft.Windows.Controls.DataGridBoundColumn)col).Binding; 有没有办法避免循环复制数据?我的网格有 46K 行,使用 for-each 需要相当长的时间。有办法吗?【参考方案2】:

我使用剪贴板找到了this。

要使代码通用,您可以修改第一个示例以读取列绑定并使用反射将它们应用于数据:

public String ExportDataGrid(DataGrid grid)

    string colPath;
    System.Reflection.PropertyInfo propInfo;
    System.Windows.Data.Binding binding;
    System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
    System.Collections.IList source = (grid.DataContext as System.Collections.IList);
    if (source == null)
        return "";

    foreach (Object data in source)
    
        foreach (DataGridColumn col in datagrid.Columns)
        
            if (col is DataGridBoundColumn)
            
                binding = (col as DataGridBoundColumn).Binding;
                colPath = binding.Path.Path;
                propInfo = data.GetType().GetProperty(colPath);
                if (propInfo != null)
                
                    strBuilder.Append(propInfo.GetValue(data, null).ToString());
                    strBuilder.Append(",");
                                        
            

        
        strBuilder.Append("\r\n");
    


    return strBuilder.ToString();

当然,它只在绑定的路径是属性名称时才有效。对于更高级的路径,您必须将绑定应用于数据(我认为这将是一个更好的解决方案,但我现在不确定如何执行此操作)。

【讨论】:

【参考方案3】:

我认为 Silverlight 不提供下载文件的方法。您可以在应用中添加一个调用 URL 的按钮,即http://www.mysite.com/generateexcelfile.aspx。将用于生成显示在 Silverlight 应用程序中的数据的参数作为 Querystring 值包含在内,运行查询并使用您最喜欢的 Excel 文件生成组件即时生成文件。重定向到它,它将下载到用户的系统。

【讨论】:

小心“创建文件然后重定向到它”——你必须在某些时候删除这些文件。更好的做法是将 Excel 保存到具有正确 mime 类型的 .aspx 页面的输出流中,以便浏览器可以看到它是 Excel 文件,而不是 html 页面,并为用户提供保存选项.【参考方案4】:

我知道这是一篇旧帖子,但它确实对我有所帮助。我进行了一些编辑以使其与 silverlight 4、converts 和 excel 一起使用。我想要快速导出,所以我首先使用 CSV,然后用 excel 打开它。 此代码适用于 silverlight web 和 oob 提升信任。在 Web 中无法在 excel 中打开。

     private static void OpenExcelFile(string Path)
    
        dynamic excelApp;
        excelApp = AutomationFactory.CreateObject("Excel.Application");
        dynamic workbook = excelApp.workbooks;
        object oMissing = Missing.Value;

        workbook = excelApp.Workbooks.Open(Path,

           oMissing, oMissing, oMissing, oMissing, oMissing,

           oMissing, oMissing, oMissing, oMissing, oMissing,

           oMissing, oMissing, oMissing, oMissing);



        dynamic sheet = excelApp.ActiveSheet;


        // open the existing sheet


        sheet.Cells.EntireColumn.AutoFit();
        excelApp.Visible = true;
    
    private static string FormatCSVField(string data)
    
        return String.Format("\"0\"",
            data.Replace("\"", "\"\"\"")
            .Replace("\n", "")
            .Replace("\r", "")
            );
    
   public  static string ExportDataGrid(DataGrid grid,string SaveFileName,bool AutoOpen)
    
        string colPath;
        System.Reflection.PropertyInfo propInfo;
        System.Windows.Data.Binding binding;
        System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
       var source = grid.ItemsSource;

        if (source == null)
            return "";

        List<string> headers = new List<string>();
        grid.Columns.ToList().ForEach(col =>
        
            if (col is DataGridBoundColumn)
            
                headers.Add(FormatCSVField(col.Header.ToString()));
            
        );
        strBuilder
        .Append(String.Join(",", headers.ToArray()))
        .Append("\r\n");

        foreach (var data in source)
        
                List<string> csvRow = new List<string>();
                foreach (DataGridColumn col in grid.Columns)
                
                    if (col is DataGridBoundColumn)
                    
                        binding = (col as DataGridBoundColumn).Binding;
                        colPath = binding.Path.Path;

                        propInfo = data.GetType().GetProperty(colPath);
                        if (propInfo != null)
                        
                            string valueConverted = "";
                            if (binding.Converter.GetType().ToString() != "System.Windows.Controls.DataGridValueConverter")
                                valueConverted = binding.Converter.Convert(propInfo.GetValue(data, null), typeof(System.String), binding.ConverterParameter, System.Globalization.CultureInfo.CurrentCulture).ToString();
                            else
                                valueConverted = FormatCSVField(propInfo.GetValue(data, null) == null ? "" : propInfo.GetValue(data, null).ToString());

                            csvRow.Add(valueConverted.ToString());
                        
                    
                
                strBuilder
                    .Append(String.Join(",", csvRow.ToArray()))
                    .Append("\r\n");
            

        if (AutomationFactory.IsAvailable)
        
            var sampleFile = "\\" + SaveFileName;
            var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            path += "\\Pement";


            if (!System.IO.Directory.Exists(path))
            
                System.IO.Directory.CreateDirectory(path);
            
            else
            
                var files = System.IO.Directory.EnumerateFiles(path);
                foreach (var item in files)
                
                    try
                    
                        System.IO.File.Delete(item);
                    
                    catch  
                
            

            StreamWriter sw = File.CreateText(path + sampleFile);
            sw.WriteLine(strBuilder.ToString());
            sw.Close();

            if (AutoOpen)
                OpenExcelFile(path + sampleFile, true, true);
        
        else
        
            SaveFileDialog sfd = new SaveFileDialog()
            
                DefaultExt = "csv",
                Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*",
                FilterIndex = 1
            ;
            if (sfd.ShowDialog() == true)
            
                using (Stream stream = sfd.OpenFile())
                
                    using (StreamWriter writer = new StreamWriter(stream))
                    
                        writer.Write(strBuilder.ToString());
                        writer.Close();
                    
                    stream.Close();
                
             
        
        return strBuilder.ToString();
    

【讨论】:

谢谢 看起来不错 试试看。请删除您的添加,请参阅此处***.com/faq#signatures 请注意,以这种方式通过互操作控制 Excel 需要用户运行浏览器外 (OOB)。您还必须构建您的应用程序,使其请求提升的权限(通过项目的属性页)。【参考方案5】:

在我的脑海中,我想说你可以使用ControlTemplate 添加导出按钮,然后遍历DataSource 中的每个项目,然后使用Columns 中的每一列来获取每个项目的内容单元格使用GetCellContent 方法,或使用DataGridColumn 的绑定信息来获取相应的单元格值。然后,您可以获取此内容的显示值并将其写入您的报告。

类似...

foreach (YourType item in grid.DataSource)

   foreach (DataGridColumn column in grid.Columns)
   
      FrameworkElement cellContent = column.GetCellContent(item);

      // Now, determine the type of cell content and act accordingly.
      TextBlock block = cellContent as TextBlock;
      if (block != null)
      
         // Report text value...
      

      // ...etc...

   

或者使用DaniCE描述的绑定信息。

【讨论】:

【参考方案6】:

检查 Ryan 的解决方案。看起来不错,但不能保证,因为我刚刚找到它。 Ryan 执行上述 DLL 要求的操作。

http://www.rshelby.com/post/exporting-data-from-silverilght-datagrid-to-excel.aspx

上面 Dakota 的解决方案中的 David 看起来更容易实现,并且总是重定向到带有数据网格且内容类型设置为 excel 的经典 asp.net 页面,但是您需要支持更多代码并且这种方式可能不适用于离线的浏览器解决方案(实际上不起作用)。

无论如何,这是一项常见的任务。我希望这里或微软的一些人提出一个 Mort 即插即用的解决方案:)

我找到了一种从 Silverlight 数据网格导出 CVS 的扩展方法-

http://www.codeproject.com/KB/silverlight/SilverlightDataGridExport.aspx

它具有即插即用的潜力,但我不得不稍微调整一下才能让它与带有项目数据源的数据网格一起工作(请参阅帖子中的 cmets)。比我更聪明、更有经验的人应该能够调整到完美。看看吧,它应该能让你接近你所需要的。

【讨论】:

【参考方案7】:

这些解决方案对我不起作用,因此我将它们修改为有效的解决方案。 (我的解决方案不需要在字段周围加上引号,所以我省略了 FormatCSVField 函数)

    public void SaveAs(string csvPath)
    
        string data = ExportDataGrid(true, _flexGrid);
        StreamWriter sw = new StreamWriter(csvPath, false, Encoding.UTF8);
        sw.Write(data);
        sw.Close();
    

    public string ExportDataGrid(bool withHeaders, Microsoft.Windows.Controls.DataGrid grid) 
    
        System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
        System.Collections.IEnumerable source = (grid.ItemsSource as System.Collections.IEnumerable);

        if (source == null) return "";

        List<string> headers = new List<string>();

        grid.Columns.ToList().ForEach(col =>
        
            if (col is Microsoft.Windows.Controls.DataGridBoundColumn)
            
                headers.Add(col.Header.ToString());
            
        );

        strBuilder.Append(String.Join(",", headers.ToArray())).Append("\r\n");
        foreach (Object data in source)
        
            System.Data.DataRowView d = (System.Data.DataRowView)data;
            strBuilder.Append(String.Join(",", d.Row.ItemArray)).Append("\r\n");
        

        return strBuilder.ToString();
    

【讨论】:

【参考方案8】:

这是一个对我有用的好方法 http://forums.silverlight.net/forums/p/179321/404357.aspx

【讨论】:

【参考方案9】:

我需要做同样的事情。我使用了 t3rse 的实现,但必须进行一些更改。我没有足够的声誉来评论他的回答,所以我会在这里列出:

对于表示 propInfo.GetValue(data, null).ToString() 的行,我在调用 ToString() 之前检查了 GetValue 返回的值是否为 Null。

李>

在方法 FormatCSVField() 中,它用三个双引号替换了一个双引号。它应该只用两个双引号替换它。

该实现仅使用 DataGridBoundColumn 类型的列,而忽略其他列。我的列不是我想要包含的 DataGridBoundColumn,因此我使用 col.SortMemberPath 获得了这些列的数据源的属性名称。

【讨论】:

以上是关于Silverlight DataGrid:导出到 excel 或 csv的主要内容,如果未能解决你的问题,请参考以下文章

DataGrid和Silverlight

Silverlight:将按钮控件与 Datagrid 单元格内的右侧对齐

Silverlight Combobox 将所选项目设置为 datagrid 的所选项目

WPF DataGrid 样式-Silverlight DataGrid?

wpf datagrid cell 设置焦点

从Silverlight到ExtJS再到BootStrap,DataTable(DataGrid)的样式格式化原理没变