使用WPF DataGrid将可见的值导出为csv文件

3

我对WPF还不太熟悉,想知道是否有可能将WPF DataGrid直接导出为csv文件。我尝试使用反射获取所需的值,虽然在某种程度上可以工作,但我想知道是否可能通过附加属性获取显示的值,这些值不一定对应于项目源的值。以下附加属性只适用于使用静态字符串或静态资源字符串等情况。如果我尝试使用列绑定,我只会得到默认字符串为空。

    public static readonly DependencyProperty ExportStringProperty =
        DependencyProperty.RegisterAttached("ExportString", //name of    attached property
        typeof(string), //type of attached property
        typeof(ExportBehaviour), //type of this owner class
        new PropertyMetadata(string.Empty)); //the default value of the attached property

    public static string GetExportString(DataGridColumn column)
    {
        return (string)column.GetValue(ExportStringProperty);
    }

    public static void SetExportString(DataGridColumn column, string value)
    {
        column.SetValue(ExportStringProperty, value);
    }

有没有类似的方法可以像这样从XAML中获取绑定值:

    <DataGridTextColumn Header="Name" Binding="{Binding (datagridexcel:Product.Name)}" datagridexcel:ExportBehaviour.ExportString="{Binding (datagridexcel:Product.Name)}"/>

如上所述,以上内容适用于静态类型字符串而非绑定。需要注意的是,在该情况下应避免使用项目源,我只关注数据表格和其中显示的值。

4个回答

7
我制作了这个简单的应用程序来演示从DataGrid获取CSV的方法。 您拥有DataGrid
<DataGrid x:Name="MyDataGrid" Grid.Row="0" ItemsSource="{Binding Rows}" />

在这个例子中,它被绑定到视图模型中的以下属性:
private IEnumerable<RowViewModel> _rows;
public IEnumerable<RowViewModel> Rows
{
    get { return _rows; }
    set
    {
        _rows = value;
        OnPropertyChanged("Rows");
    }
}

行被设置为以下示例数据:

Rows = new List<RowViewModel>
{
    new RowViewModel { FirstName = "John", LastName = "Doe", DateOfBirth = new DateTime(1988, 12, 19) },
    new RowViewModel { FirstName = "Lara", LastName = "Croft", DateOfBirth = new DateTime(1975, 5, 3) },
    new RowViewModel { FirstName = "Sam", LastName = "Fisher", DateOfBirth = new DateTime(1967, 2, 9) }
};

DataGrid 下面有一个 Button

<Button Grid.Row="1" Content="Copy values as CSV" Command="{Binding CopyAsCsvCommand}" CommandParameter="{Binding ElementName=MyDataGrid}" />

它绑定到视图模型中的Command,而CommandParameter是整个DataGrid

CopyAsCsvCommand = new DelegateCommand<DataGrid>(CopyAsCsvHandler);
Command 的处理方法是实际复制发生的地方:
private void CopyAsCsvHandler(DataGrid dg)
{
    dg.SelectAllCells();
    dg.ClipboardCopyMode = DataGridClipboardCopyMode.IncludeHeader;
    ApplicationCommands.Copy.Execute(null, dg);
    dg.UnselectAllCells();
    LivePreviewText = (string)Clipboard.GetData(DataFormats.CommaSeparatedValue);
}

这相当于使用CTRL+A选择所有单元格,然后按下CTRL+C。

示例

示例图片

现在您已经获得了CSV内容,您只需将其保存为带有CSV扩展名的文件即可。我希望这可以帮助您,也是您正在寻找的内容。


谢谢您花时间回复,不过我应该提到我已经尝试过这个了。虽然这个方法可以正常工作,但是有一个问题,就是复制和粘贴无法处理DataGridTemplateColumn的情况。所以对于这种情况,我想定义应该导出哪些内容。 - Sjokoladefoged
1
这可以通过使用DataGridColumnClipboardContentBinding属性来解决。例如,如果列A绑定到一个复杂对象(如具有FirstName属性的Person),则可以在列A上定义ClipboardContentBinding{Binding FirstName},以便在按下CTRL+C时复制该对象的FirstName。据我所知 :) - Szabolcs Dézsi
那可能是一种选择,但我想避免使用复制到剪贴板的方法。 - Sjokoladefoged
注意CLIPBRD_E_CANT_OPEN错误。 - itsho

4

这对我很有帮助。数据网格导出到CSV(WPF)

   private void button_Click(object sender, RoutedEventArgs e)
    {       
        dataGrid1.SelectAllCells();
        dataGrid1.ClipboardCopyMode = DataGridClipboardCopyMode.IncludeHeader;
        ApplicationCommands.Copy.Execute(null, dataGrid1);
        dataGrid1.UnselectAllCells();
        String result = (string)Clipboard.GetData(DataFormats.CommaSeparatedValue);
        File.AppendAllText("D:\\test.csv", result, UnicodeEncoding.UTF8);

    }

这个解决方案很好,但它会清空剪贴板。有没有一种方法可以避免这种情况发生? - Jeff
注意:此解决方案保存并恢复剪贴板,但不是100%可靠的。https://stackoverflow.com/questions/65162830/save-original-clipboard-with-text-or-image-and-restore-it-later-in-c-sharp - Jeff

0

我使用反射成功解决了这个问题。

假设我们有一个 DataGrid,具备以下条件:

  • 列的显示名称可能与绑定到 DataGrid 的对象集合中包含的属性名称不同。
  • 列可以重新排列。
  • 有时候,但并非总是,列可以被隐藏。
  • 任何单元格都可以包含任何符号,包括换行符和双引号。

此解决方案创建了一个逗号分隔的字符串,完全按照屏幕上的显示方式显示 DataGrid,而不会覆盖剪贴板中的任何内容。

const string delimiter = ",";
var sb = new StringBuilder();

var visibleColumns = OutputGrid.Columns.Where(c => c.Visibility == Visibility.Visible);

var columnHeaders = columnHeaders.Select(c => c.Header);

sb.AppendLine(String.Join(delimiter, columns.Select(c => String.Format("\"{0}\"", c != null ? c.ToString().Replace("\"", "'") : String.Empty))));

var rows = OutputGrid.Items.Cast<TypeThatsBoundToTheDataGrid>()
                           .Select(item => item.GetType().GetProperties()                                         
                                                         .Where(p => visibleColumns.Select(c => c.SortMemberPath)
                                                                                   .Contains(p.Name))
                                                         .OrderBy(p => OutputGrid.Columns                         
                                                                                 .Select(c => c.SortMemberPath)
                                                                                 .ToList()
                                                                                 .IndexOf(p.Name))
                                                         .Select(p => p.GetValue(item)));

foreach (var row in rows)
{
    sb.AppendLine(String.Join(delimiter, row.Select(val => String.Format("\"{0}\"", val != null ? val.ToString().Replace("\"", "'") : String.Empty))));
}

string csvData = sb.ToString();

// Save this string however you want.

0
这是对jb_ice_yyc完成的解决方案的更正。
代码
public static void ExportToCSV(DataGrid dataGrid)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "CSV Files (*.csv)|*.csv";

            if (openFileDialog.ShowDialog() == true)
            {
                string filePath = openFileDialog.FileName;

                try
                {
                    const string delimiter = ",";
                    var sb = new StringBuilder();

                    var visibleColumns = dataGrid.Columns.Where(c => c.Visibility == Visibility.Visible);

                    var columnHeaders = visibleColumns.Select(c => c.Header);

                    sb.AppendLine(String.Join(delimiter, columnHeaders.Select(c => String.Format("\"{0}\"", c != null ? c.ToString().Replace("\"", "'") : String.Empty))));

                    var rows = dataGrid.Items.Cast<cStudente>()
                                               .Select(item => item.GetType().GetProperties()
                                                                             .Where(p => visibleColumns.Select(c => c.SortMemberPath)
                                                                                                       .Contains(p.Name))
                                                                             .OrderBy(p => dataGrid.Columns
                                                                                                     .Select(c => c.SortMemberPath)
                                                                                                     .ToList()
                                                                                                     .IndexOf(p.Name))
                                                                             .Select(p => p.GetValue(item)));

                    foreach (var row in rows)
                    {
                        sb.AppendLine(String.Join(delimiter, row.Select(val => String.Format("\"{0}\"", val != null ? val.ToString().Replace("\"", "'") : String.Empty))));
                    }

                    string csvData = sb.ToString();
                    using (StreamWriter sw = new StreamWriter(filePath))
                    {
                        sw.WriteLine(csvData);
                    }
                    MessageBox.Show("Data exported to CSV successfully.", "Export Complete", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("An error occurred while exporting the data: " + ex.Message, "Export Error", MessageBoxButton.OK, MessageBoxImage.Error);
                }
            }



        }

这是已批准的。

你的回答可以通过提供更多支持性信息来改进。请编辑以添加进一步细节,例如引用或文档,以便他人可以确认你的答案是否正确。你可以在帮助中心找到关于如何撰写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接