In the v1 release (and CTP) of the WPF DataGrid there will be support for Clipboard.Copy but no support out of the box for Clipboard.Paste. However, there is extensibility support for Clipboard.Paste which I will show how to implement in this post.
In DataGridColumn.cs an additional API, OnPastingCellClipboardContent, exists so you can add pasting functionality to each DataGridCell. A similar API, OnCopyingCellClipboardContent, also exists and behaves the same way except it is used from copying content. OnPastingCellClipboardContent has two parameters; item, which is the particular data item in the list of DataGrid.Items to update, and cellContent, which is the actual content to add to the cell itself.
So with that in mind, what I need to do is get the content currently on the clipboard, parse the data, and then call OnPastingCellClipboardContent for each cell. I’m also going to setup a command that is similar to the Copy command and I’ve decided to subclass DataGrid. Here is the code for creating the command:
public class CustomDataGrid : DataGrid
new CanExecuteRoutedEventHandler(OnCanExecutePaste))); }
In the copy scenario, the OnCanExecuteCopy only fires if you have selected cells. For the onCanExecutePaste scenario I want it to be such that you can paste content as long as any particular cell is selected. So in my OnCanExecutePaste method, I only need the CurrentCell to not be null.
protected virtual void OnCanExecutePaste(CanExecuteRoutedEventArgs args)
args.CanExecute = CurrentCell != null;
args.Handled = true;
Before getting into OnExecutePaste, I want to talk just a little bit about the parsing stuff. I created a simple parser for CSV and Text format. The algorithms are pretty straightforward so I’m not going to show them here. The parser should work when copying data from the WPF DataGrid as well as copying Excel data to the WPF DataGrid. For Excel data I’m using the Text parser. What the parser returns is a list of a list which basically represent the rows and cells of a DataGrid.
So in my OnExecutePaste method, I am going to iterate through the set of cells starting at the CurrentCell. It is possible that the set of content to be pasted is more than the set of cells to paste them in or visa-versa. So I need to keep track of the max rows and columns that can be pasted to as well as the max data that can be placed in the cells. Here is the code snippet:
protected virtual void OnExecutedPaste(ExecutedRoutedEventArgs args)
// parse the clipboard data
List<string> rowData = ClipboardHelper.ParseClipboardData();
// call OnPastingCellClipboardContent for each cell
int minRowIndex = Items.IndexOf(CurrentItem);
int maxRowIndex = Items.Count - 1;
int minColumnDisplayIndex = (SelectionUnit != DataGridSelectionUnit.FullRow) ? Columns.IndexOf(CurrentColumn) : 0;
int maxColumnDisplayIndex = Columns.Count - 1;
int rowDataIndex = 0;
for (int i = minRowIndex; i < maxRowIndex && rowDataIndex < rowData.Count; i++, rowDataIndex++)
int columnDataIndex = 0;
for (int j = minColumnDisplayIndex; j < maxColumnDisplayIndex && columnDataIndex < rowData[rowDataIndex].Length; j++, columnDataIndex++)
DataGridColumn column = ColumnFromDisplayIndex(j);
I did make one condition when SelectionUnit is equal to FullRow. For that scenario when users copy a full row and paste to another full row the column index should not matter as their intention is to paste the entire row to the new row. So for that I set minColumnDisplayIndex to 0.
You can check out the full sample here. For more information on clipboard paste see this post which is another sample.
Other DataGrid Samples:
ScrollViewer with ToolTip
Custom sorting, column selection, single-click editing
Styling rows and columns based on header conditions