WPF Datagrid:将其他行复制到剪贴板

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13178363/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:01:58  来源:igfitidea点击:

WPF Datagrid: copy additional rows to clipboard

wpfdatagridclipboard

提问by mhttk

I am working with the WPF Datagrid and I am trying to enhance/change the copy & paste mechanism.

我正在使用 WPF Datagrid,我正在尝试增强/更改复制和粘贴机制。

When the user selects some cells and then hit CTRL + C, the underlying controls is able to catch the CopyingRowClipboardContentevent.

当用户选择一些单元格然后按 CTRL + C 时,底层控件能够捕获CopyingRowClipboardContent事件。

 this.mainDataGrid.CopyingRowClipboardContent 
              += this.DatagridOnCopyingRowClipboardContent;

In this method, some cells are added to both the header and the rows, hence resulting in a "wider" grid.

在这种方法中,一些单元格被添加到标题和行中,从而导致“更宽”的网格。

    private void DatagridOnCopyingRowClipboardContent(
        object sender, 
        DataGridRowClipboardEventArgs dataGridRowClipboardEventArgs)
    {
        // this is fired every time a row is copied
        var allContent = dataGridRowClipboardEventArgs.ClipboardRowContent;

        allContent.Insert(0, new DataGridClipboardCellContent(
                                            null, 
                                            this.mainDataGrid.Columns[0], 
                                            "new cell"));
    }

At this point I am stuck because I am trying to add an additional row beforethe header and two afterthe last row (see image below).

在这一点上,我被卡住了,因为我试图在标题之前添加一个额外的行在最后一行之后添加两个(见下图)。

Any ideas? Suggestions?

有任何想法吗?建议?

Please note I am not interested in an MVVM way of doing it here.

请注意,我对在这里使用 MVVM 的方式不感兴趣。

enter image description here

在此处输入图片说明

采纳答案by Damascus

Here is a code snippet that might help you. This snippet is mainly used to retrieve all of your selected data, including headers (I removed the RowHeaderspart since you apparently don't need it). If you have any question please let me know. I left a few part with comments written in capital letters: this is where you should add your own data The good part of this approach is that it directly works with your DataGrid's ItemsSourceand NOT the DataGridCell. The main reason being: if you use DataGridCellon a formatted number for example, you will NOT get the actual value, but just the formatted one (say your source is 14.49 and your StringFormatis N0, you'll just copy 14 if you use a "regular" way)

这是一个可能对您有所帮助的代码片段。此代码段主要用于检索您选择的所有数据,包括标题(我删除了该RowHeaders部分,因为您显然不需要它)。如果您有任何问题,请告诉我。我留下了一些用大写字母写的注释的部分: 这是您应该添加自己的数据的地方 这种方法的好处在于它直接适用于您的DataGrid'sItemsSource而不是DataGridCell. 主要原因是:DataGridCell例如,如果您使用格式化的数字,您将不会获得实际值,而只会获得格式化的值(假设您的来源是 14.49,而您的来源StringFormat是 N0,如果您使用“常规”方式)

   /// <summary>
    /// Handles DataGrid copying with headers
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnCopyingDataGrid(object sender, ExecutedRoutedEventArgs e)
    {
        // First step: getting the coordinates list of all cells selected
        IList<Tuple<int, int>> cellsCoordinatesList = new List<Tuple<int, int>>();
        HashSet<int> rowList = new HashSet<int>();
        HashSet<int> columnList = new HashSet<int>();
        foreach (System.Windows.Controls.DataGridCellInfo cell in this.SelectedCells)
        {
            int column = cell.Column.DisplayIndex;
            int row = this.Items.IndexOf(cell.Item);
            cellsCoordinatesList.Add(new Tuple<int, int>(row, column));
            if (!rowList.Contains(row))
            {
                rowList.Add(row);
            }
            if (!columnList.Contains(column))
            {
                columnList.Add(column);
            }
        }

        // Second step: Create the table to copy/paste
        object[,] arrayToBeCopied = new object[rowList.Count, columnList.Count + 1];
        IList<string> colHead = this.ColumnHeaders.Cast<object>().Select(h => h.ToString()).ToList();
        for (int row = 0; row < arrayToBeCopied.GetLength(0); row++)
        {
            for (int column = 0; column < arrayToBeCopied.GetLength(1); column++)
            {
                if (row == 0)
                {
                    arrayToBeCopied[row, column] = colHead[columnList.ElementAt(column - 1)];
                }
                else
                {
                    arrayToBeCopied[row, column] = // WHATEVER YOU WANT TO PUT IN THE CLIPBOARD SHOULD BE HERE. THIS SHOULD GET SOME PROPERTY IN YOUR ITEMSSOURCE

                }
            }
        }

        // Third step: Converting it into a string
        StringBuilder sb = new StringBuilder();

        // HERE, ADD YOUR FIRST ROW BEFORE STARTING TO PARSE THE COPIED DATA

        for (int row = 0; row < arrayToBeCopied.GetLength(0); row++)
        {
            for (int column = 0; column < arrayToBeCopied.GetLength(1); column++)
            {
                sb.Append(arrayToBeCopied[row, column]);
                if (column < arrayToBeCopied.GetLength(1) - 1)
                {
                    sb.Append("\t");
                }
            }
            sb.Append("\r\n");
        }

        // AND HERE, ADD YOUR LAST ROWS BEFORE SETTING THE DATA TO CLIPBOARD

        DataObject data = new DataObject();
        data.SetData(DataFormats.Text, sb.ToString());

        Clipboard.SetDataObject(data);
    }

回答by skofgar

Are you trying to copy the content into e.g. Excel later? If so, here's what I did:

您是否尝试稍后将内容复制到例如 Excel 中?如果是这样,这就是我所做的:

/// <summary>
/// Copy the data from the data grid to the clipboard
/// </summary>
private void copyDataOfMyDataGridToClipboard(object sender, EventArgs e)
{
    // Save selection
    int selectedRow = this.myDataGrid.SelectedRows[0].Index;

    // Select data which you would like to copy
    this.myDataGrid.MultiSelect = true;
    this.myDataGrid.SelectAll();

    // Prepare data to be copied (that's the interesting part!)
    DataObject myGridDataObject = this.myDataGrid.GetClipboardContent();
    string firstRow = "FirstRowCommentCell1\t"+ this.someDataInCell2 +"..\r\n";
    string lastTwoRows = "\r\nBottomLine1\t" + yourvariables + "\r\nBottomLine2";
    string concatenatedData = firstRow + myGridDataObject.GetText() + lastTwoRows;

    // Copy into clipboard
    Clipboard.SetDataObject(concatenatedData);

    // Restore settings
    this.myDataGrid.ClearSelection();
    this.myDataGrid.MultiSelect = false;

    // Restore selection
    this.myDataGrid.Rows[selectedRow].Selected = true;
}

In my case I had some static header's which could be easily concatenated with some variables. Important to write are the \tfor declaring another cell, \r\ndeclares the next row

就我而言,我有一些静态标头,它们可以很容易地与一些变量连接起来。重要的是\t要声明另一个单元格,\r\n声明下一行

回答by Markus

I realize this an older post, but I post this solution for completeness. I could not find a more recent question on copying datagrid rows to clipboard. Using Clipboard.SetData belies the ClipboardRowContent intention.

我意识到这是一篇较旧的帖子,但为了完整性,我发布了此解决方案。我找不到有关将数据网格行复制到剪贴板的最新问题。使用 Clipboard.SetData 掩盖了 ClipboardRowContent 的意图。

For my needs, I'm re-pasting back into the e.ClipboardRowContent the row I would like. The cell.Item is all the information I need for each selected row.

根据我的需要,我将我想要的行重新粘贴回 e.ClipboardRowContent。cell.Item 是每个选定行所需的所有信息。

Hint: I was getting duplicates without doing an e.ClipboardRowContent.Clear(); after using the e.ClipboardRowContent . I was clearing before and using DataGrid.SelectedItems to build the rows.

提示:我在没有执行 e.ClipboardRowContent.Clear() 的情况下得到了重复项;使用 e.ClipboardRowContent 后。我之前清除并使用 DataGrid.SelectedItems 来构建行。

private void yourDataGrid_CopyingRowClipboardContent(object sender,    DataGridRowClipboardEventArgs e)
{
var dataGridClipboardCellContent = new List<DataGridClipboardCellContent>(); 

string prevCell = "";
string curCell = ""; 

foreach (DataGridClipboardCellContent cell in e.ClipboardRowContent)
{
    //Gives you access item.Item or item.Content here
    //if you are using your struct (data type) you can recast it here curItem = (yourdatatype)item.Item;        
    curItem = cell.Item.ToString(); 

    if (curCell != prevCell)
        dataGridClipboardCellContent.Add(new DataGridClipboardCellContent(item, item.Column, curCell)); 

    prevCell = curCell;  

}
e.ClipboardRowContent.Clear();

//Re-paste back into e.ClipboardRowContent, additionally if you have modified/formatted rows to your liking
e.ClipboardRowContent.AddRange(dataGridClipboardCellContent);

}

}