Welcome to MSDN Blogs Sign in | Join | Help

Vincent Sibal's Blog

WPF Programming Topics
WPF DataGrid – New Item Template Sample

This sample shows how to create a template for the NewItemPlaceholder to indicate that you can add a new item.  This is what it will look like:

newitemtemplate

First I will need to create a new template specifically for the NewItemPlaceholder row.  I’ve followed the general outline of the original DataGridRow control template but I’ve only included the pieces I needed and I’ve also added an element for the “Click here to add new item.” text.  My template looks something like this:           

<ControlTemplate x:Key="NewRow_ControlTemplate" TargetType="{x:Type dg:DataGridRow}">

  <Border x:Name="DGR_Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True">

      <dg:SelectiveScrollingGrid>

       

        <TextBlock Text="Click here to add a new item." Grid.Column="1"/>

       

      </dg:SelectiveScrollingGrid>

</ControlTemplate>

 

Then I’m going to need to attach to several events.  In particular, I need to hook up to the DataGrid.LoadingRow, DataGrid.UnloadingRow, DataGrid.RowEditEnding, and DataGridRow.MouseLeftButtonDown events. 

I attach to the LoadingRow and UnloadingRow events so I can set either the default or new item control template when the row is created.  These event handlers will look like this:

private void DataGrid_Standard_LoadingRow(object sender, DataGridRowEventArgs e)

{

  if (_defaultRowControlTemplate == null)

  {

      _defaultRowControlTemplate = e.Row.Template;

  }

  if (e.Row.Item == CollectionView.NewItemPlaceholder)

  {

      e.Row.Template = _newRowControlTemplate;

      e.Row.UpdateLayout();

  }

}

 

private void DataGrid_Standard_UnloadingRow(object sender, DataGridRowEventArgs e)

{

  if (e.Row.Item == CollectionView.NewItemPlaceholder && e.Row.Template != _defaultRowControlTemplate)

  {

      e.Row.Template = _defaultRowControlTemplate;

      e.Row.UpdateLayout();

  }

}

 

I attach to the DataGridRow.MouseLeftButtonDown event so that I can change the template of the NewItemPlaceholder on the first click.  For this sample, when first clicking the row of the NewItemPlaceholder it immediate enters edit mode.  Here is the handler:

private void Row_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

{

  DataGridRow row = sender as DataGridRow;

  if (row.Item == CollectionView.NewItemPlaceholder && row.Template == _newRowControlTemplate)

  {

      // for a new row update the template and open for edit

      row.Template = _defaultRowControlTemplate;

      row.UpdateLayout();

 

      DataGrid_Standard.CurrentItem = row.Item;

      DataGridCell cell = Helper.GetCell(DataGrid_Standard, DataGrid_Standard.Items.IndexOf(row.Item), 0);

      cell.Focus();

      DataGrid_Standard.BeginEdit();

  }

}

 

The last event is necessary so that the template is updated back to the new item template after a row is either committed or cancelled.  It is a little tricky because what I really want is to perform my operation when the row is already committed or cancelled but the only event available, RowEditEnding, fires while the row is committing or being cancelled.  What I can do is use the Dispatcher to make my operation take place after the RowEditEnding event.  My handler looks like this:          

private void DataGrid_Standard_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)

{

  IEditableCollectionView iecv = CollectionViewSource.GetDefaultView((sender as DataGrid).ItemsSource) as IEditableCollectionView;

  if (iecv.IsAddingNew)

  {

      // need to wait till after the operation as the NewItemPlaceHolder is added after

      Dispatcher.Invoke(new DispatcherOperationCallback(ResetNewItemTemplate), DispatcherPriority.ApplicationIdle, DataGrid_Standard);

  }

}

 

private object ResetNewItemTemplate(object arg)

{

  DataGridRow row = Helper.GetRow(DataGrid_Standard, DataGrid_Standard.Items.Count - 1);

  if (row.Template != _newRowControlTemplate)

  {

      row.Template = _newRowControlTemplate;

      row.UpdateLayout();

   }

  return null;

}

 

So when I cancel or commit the edit on the new item, the new item template will be added back to the last row. 

You can download the full sample here.

Posted: Wednesday, November 05, 2008 7:33 AM by vinsibal
Attachment(s): DataGrid_V1_NewItemTemplate_Sample.zip

Comments

Rudi Grobler said:

Wow, Nice!!!

Tnx Vincent,

Rudi

# November 6, 2008 1:28 AM

vinsibal said:

Rudi, thanks for your encouragement!

# November 6, 2008 8:46 AM

Egil Hansen said:

Hi Vincent

This is very cool. I am wondering if it is possible to get the DataGrid to do grouping like you see in Outlook, where mails are grouped by the day they where received.

Would love to see an example of that if you could.

# November 6, 2008 9:59 AM

Peter said:

Great post! It's like you read my mind. I came into work this morning thinking that I needed to figure out how to style the "New Item" row in my grids. Thanks!

# November 6, 2008 10:37 AM

Peter said:

This works ... but is there an easier way to handle this if you just want to re-style the NewItemPlaceholder row (like change the Background and Header) rather than re-templating it? I've tried doing so with a DataTrigger in my RowStyle but haven't had much luck yet.

Now that I think about it, it would be nice to have a NewRowStyle attribute on the DataGrid ...

# November 6, 2008 12:51 PM

vinsibal said:

Peter,

There are a couple things that you can do.  You can use a StyleSelector on DataGrid.RowStyleSelector or you can listen to the LoadingRow event and for a NewItemPlaceholder row, set the background there.  

# November 6, 2008 1:16 PM

sree said:

Hi Vincent,

I am a newbie in wpf and currently working on a wpf application which is having a Datagrid . After performing a successful drag-drop, i need to disable that particular row in the datagrid . I tried but am unable to . Could you please advise me on this.

regards

sree

# December 18, 2008 1:05 AM

vinsibal said:

sree,

When you say drag-drop, you want to drag and drop a new row and have that row be disabled?  You will have to keep track of it and maybe set a DataTrigger to set IsEnabled to false when that flag is set.  This sample could maybe help, http://blogs.msdn.com/vinsibal/archive/2008/12/18/wpf-datagrid-sample-locking-input-to-the-row-being-edited.aspx.  But it only keeps track of one row really.  You need to keep track of all rows that are dragged.

# December 19, 2008 12:50 PM

marco.ragogna said:

Hi Vincent, great article!

I have only one question about a problem I am facing.

I have bound the grid to my observablecollection, then implemented LoadingRow and UnloadingRow.

When I clear all object in the grid using the observable collection clear function I get an exception the code:

row.UpdateLayout()

of UnloadingRow. You can get the same effect if you delete manually all rows of your example code and click one column header for sorting.

I solve this by defining a new function:

Private Function ResetDefaultItemTemplate(ByVal sender As Object) As Object

       Dim grid As DataGrid = TryCast(sender, DataGrid)

       If grid Is Nothing Then Debug.Assert(False, "DataGrid parameter has not been correctly set.")

       Dim row As DataGridRow = DataGridHelper.GetRow(grid, grid.Items.Count - 1)

       If Not row.Template.Equals(_DefaultRowControlTemplate) Then

           row.Template = _DefaultRowControlTemplate

           row.UpdateLayout()

       End If

       Return Nothing

   End Function

and calling it with

Dispatcher.Invoke(New DispatcherOperationCallback(AddressOf ResetDefaultItemTemplate), DispatcherPriority.Send, dgCategories)

before clearing the bound collection. What do you think about? Is it clean? Is it really a bug of our implementation or it is a bug of WPF DataGrid?

Thanks a lot in advance and sorry for the long post.

# January 16, 2009 4:01 AM

jackass said:

Can someone give me a reference on where I can learn where all these datagrid events are. Everytime I go to look at examples to learn about the datagrid there is alway new event poping up and there seems a 1 to 100 ways to the same thing for the same event.

# February 25, 2009 8:26 PM

Jaime Rodriguez said:

You know the drill.. raw, unedited, yet deep and useful WPF conversations !! Subject: Changing Resources

# April 6, 2009 2:36 AM

Vincent Sibal's Blog said:

UPDATE: the WPF DataGrid v1 has just released. For more information, see this post . The information

# April 10, 2009 10:14 AM

Gaurav.Mantri said:

Hi Vincent,

Is there any way I can hide this "NewItemTemplate". I am providing a separate button (in grid header) to insert a row.

Please let me know.

Thanks

Gaurav Mantri

# June 30, 2009 4:26 AM

vinsibal said:

Gaurav,

You can set DataGrid.CanAddNewRow to false.

# June 30, 2009 8:03 AM

Tobias said:

Hi Vincent,

thanks a lot of the helpful article. I have a question: What happens to the new item template if the ItemsSource is empty (of course with CanUserAddRows="True")?? In your sample source code, I commented out the method CreateGenericPersonData in the constructor of class DataGridSample.EditablePeople:

       public EditablePeople()

       {

           //CreateGenericPersonData(1);

       }

       public EditablePeople(int multiplier)

       {

           //CreateGenericPersonData(multiplier);

       }

If I do this, the view is empty (as desired). However, the New Item Template row "Click here to add a new item" does not show up, so I am not able to add a new row. There must be at least ONE entry in the view so that this template appears.

How can I have the new item template row in the view if the initial DataGrid.Items is empty? Thanks!

# July 15, 2009 12:23 PM

Mahender said:

I need a Help ,Whenever a New Row is Added to Datagrid.DatagridCell which are binded to DataContext property are unable to bind ,it gives us Error in Output window Unable to find property ,How to handle thos issue.I knew new item is NewItemPlaceHolder.How to Initialise newItemPlaceHolder.Is there a Event

With Regards,

Mahens

# July 17, 2009 4:00 PM

Ferde said:

Why is that when I limit the people records, like for example just 3 rows only, the "left Column header corner" is not visibly when you apply the NewRow_ControlTemplate. thus it result to column misalignment..

# July 20, 2009 3:29 AM

vinsibal said:

Mahender,

This is a known bug that has been fixed in the dev10 timeframe.  Currently there isn't any easy workarounds.

# July 20, 2009 8:42 AM

Mahender said:

Thanks Vincent.Some more issue with NewRowTemplate.Issues are Im also facing same issue as Ferde is facing.i.e whenever a newtemplate is added.TopLeftcolumn Button disappear which makes column alignment problems.

My Second issue is,If I try add new row,New row(Particular cell) is binded to one property of domain object.If there are some validation errors on particular cell and change focus ,NewRowTemnplate is not visible until i fix the validation error in that cell.

can u please provide me workaround even after validation error i want show new row template

Thanks in adavance,

With Regards,

Mahender

# July 21, 2009 10:07 AM

Lance Contreras said:

Hi Vincent,

Is it possible to put the newrowtemplate on top of the datagridview(row 0) instead of the last of placing it in the last row?

# August 25, 2009 4:10 AM

vinsibal said:

Lance,

It is possible by setting the NewItemPlaceHolderPosition on the IECV but it is not recommended as there are some scenarios that will not work properly with the NewItemPlaceHolder at the beginning.  One of them is the fact that after you add the new item it will still be placed at the bottom.

# September 8, 2009 9:40 AM

MartonSzabo said:

Hi Vincent,

I would like to ask something interesting. I would like to create an empty grid by default, and start adding rows. If the itemsource I specify is an empty collection, datagrid does not add a newitemtemplate row by default. I tried in your code, if I delete line:

CreateGenericPersonData(1); from the editablepeople constructor, the problem is reproduced easily.

Do you have any idea how can I add the new item template to an empty grid using item source?

Thank you very much,

Marton

# October 14, 2009 5:04 AM

vinsibal said:

Marton,

Try using an ObservableCollection<T> directly instead of a class that derives from it.  And make sure T implements IEditableObject.  If you have any issues let me know.

# October 21, 2009 5:09 AM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

  
Enter Code Here: Required

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker