Click here to Skip to main content
15,860,972 members
Articles / Desktop Programming / WPF

Implementing Copy and Paste for a WPF DataGrid in .NET 4

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
31 Aug 2011CPOL4 min read 89.8K   4.9K   21   11
Using the DataZGrid provided by .NET 4, this article shows how to copy and paste between cells.

Introduction

Update - See restriction 3 below.

Using the standard DataGrid that was added with .NET 4, I found that I needed to implement copy and paste. Searching the internet came up with solutions that either worked with Silverlight or with some sort of pre-release version that you could add to Visual Studio 2008 (.NET 3).

To my horror, I had to actually figure something out and write some code. I'm very new to WPF and have spent the last few months copying example code off the internet and modifying it for my use but I think I have finally written something that might be of use to other people, so here it is.

Credit goes to the following two pages that helped, and some code was taken from the second one (credited in comments):

The solution allows you to do some limited copy and pasting between cells. In the example, I have a table of people with fields first name, second name, and legs (a number - usually 2). In the application I was working on, it made no sense to copy from one column to another. So in this example, you can't copy the legs column to the first name column (for example). This is intentional and the restriction could be removed easily by deleting some checks.

Restrictions / problems to solve!

  1. It only deals with strings or integers. It should be easy to expand on the types allowed with more code but perhaps that can be avoided completely with a different implementation.
  2. The clipboard is only converted from one particular format. I need to see if copying from Excel works - otherwise I probably need to put some code back into DatagridHelper that I removed!
  3. Important If the rows are re-ordered, it breaks this code! For this reason, I suggest you don't use this code.

Reto Ravisio saw this article and provided a much better solution. I have taken that, changed it slightly, and provided a complete solution file that uses his code:

Hopefully this will help beginners like myself use that code.

Using the code

I will go over some of the code you have to copy into your project, but you'll have to see the entire solution to get all the required code. This is a tester to show you the main principles so you can decide if it's for you.

The DataGrid is declared like this:

XML
<DataGrid Name="dataGrid1" ItemsSource="{Binding PeopleList}" 
                  SelectionUnit="Cell"
                  AutoGenerateColumns="True" 
                  KeyDown="dataGrid1_KeyDown" 
                  CopyingRowClipboardContent="dataGrid1_CopyingRowClipboardContent" 
                  ColumnReordered="dataGrid1_ColumnReordered"/>

Note that the SelectionUnit is set to Cell. This allows individual cells to be selected rather than the whole row. The items are taken from an ObserverableCollection and the columns are automatically generated.

The KeyDown event is set to detect the paste operation:

C#
void dataGrid1_KeyDown(object sender, KeyEventArgs e)
{
  if (e.Key == Key.V &&
      (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
  {
    if (ValidatePaste() == false)
      return;

    viewModel.Paste(dataGrid1.CurrentColumn.DisplayIndex,
         GetTargetRow(),
         dataGrid1.SelectedCells.Count,
         Clipboard.GetData(DataFormats.Text) as string);
  }
}

As you can see, a View Model is used.

The View Model Paste function uses the ClipboardHelper class (taken from the MSDN blog mentioned in the introduction) to convert the string version of the copied cells into a list of string arrays representing the cells on each row. Then it loops through the target rows setting the ObservableCollection.

Reflection is used to set the properties in the collection having only a string representing the property name. This avoids having a switch statement checking the display index value and matching that up to a property. It would have made the code very tedious to write and not easily re-usable.

The SetProperty function implements that functionality:

C#
private void SetProperty(Person person, string propertyName, string cellItem)
{
  // Use reflection to set the property to the value
  Type type = person.GetType();
  PropertyInfo prop = type.GetProperty(propertyName);
  if (prop == null)
  {
    Debug.WriteLine("Property not found: " + propertyName);
    return;
  }
  if (prop.PropertyType == typeof(string)) // only caters for string or integer types
    prop.SetValue(person, cellItem, null);
  else
    prop.SetValue(person, int.Parse(cellItem), null);
  person.OnPropertyChanged(propertyName);
}

You can see in the code above where the restriction on having only strings or integers comes from.

The People class is a simple container class that implements INotifyPropertyChanged:

C#
class Person : INotifyPropertyChanged
{
    public Person(string first, string second)
    {
      FirstName = first;
      SecondName = second;
      Legs = 2;
    }
    public string FirstName { set; get; }
    public string SecondName { set; get; }
    public int Legs { set; get; }

#region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

#endregion
}

The code which populates the map of property names and display indexes (used in the VM Paste function) relies on this bit of code in the code-behind:

C#
private void dataGrid1_ColumnReordered(object sender, DataGridColumnEventArgs e)
{
    viewModel.ClearColumnMapping();
    foreach (DataGridColumn col in dataGrid1.Columns)
    {
        viewModel.AddColumnMapping(col.DisplayIndex, col.SortMemberPath);
    }
}

I'm assuming that the SortMemberPath will always be the same as the property name in the People class. It was in my case.

History

  • 2011-09-01: A new version which gets the column information when the columns are re-ordered rather than when loaded. Updated a downloadable complete solution based on Reto's article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionThank you Pin
Grant Mc27-Jul-22 17:49
Grant Mc27-Jul-22 17:49 
QuestionBest Way? Pin
Reto Ravasio28-Aug-11 1:04
Reto Ravasio28-Aug-11 1:04 
AnswerRe: Best Way? Pin
Peter_Smithson28-Aug-11 21:30
Peter_Smithson28-Aug-11 21:30 
GeneralRe: Best Way? Pin
Reto Ravasio29-Aug-11 7:44
Reto Ravasio29-Aug-11 7:44 
GeneralRe: Best Way? Pin
Peter_Smithson30-Aug-11 21:24
Peter_Smithson30-Aug-11 21:24 
GeneralRe: Best Way? Pin
Peter_Smithson30-Aug-11 23:11
Peter_Smithson30-Aug-11 23:11 
GeneralRe: Best Way? Pin
Reto Ravasio31-Aug-11 12:44
Reto Ravasio31-Aug-11 12:44 
GeneralRe: Best Way? Pin
Peter_Smithson31-Aug-11 22:13
Peter_Smithson31-Aug-11 22:13 
GeneralRe: Best Way? Pin
Reto Ravasio1-Sep-11 10:14
Reto Ravasio1-Sep-11 10:14 
GeneralRe: Best Way? Pin
Peter_Smithson5-Sep-11 5:54
Peter_Smithson5-Sep-11 5:54 
AnswerRe: Best Way? Pin
Member 85358323-Jan-12 2:43
Member 85358323-Jan-12 2:43 
I'm looking at this same issue but need to deal with thousands of rows of data. Pasting through the grid doesn't appear to be able to handle this so I'm modifying the ObservableCollection as in Peter's original example. For 4000 rows of 30 columns this method executes seemingly instantly vs several minutes per 200 rows for the paste into grid version.
I see the issue with sorting but we don't have need for sorting or column reordering for this data entry grid.
Worth considering before deciding there's a best method.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.