Compartilhar via


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.

DataGrid_V1_NewItemTemplate_Sample.zip

Comments

  • Anonymous
    November 05, 2008
    PingBack from http://mstechnews.info/2008/11/wpf-datagrid-%e2%80%93-new-item-template-sample/

  • Anonymous
    November 05, 2008
    Wow, Nice!!! Tnx Vincent, Rudi

  • Anonymous
    November 06, 2008
    Rudi, thanks for your encouragement!

  • Anonymous
    November 06, 2008
    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.

  • Anonymous
    November 06, 2008
    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!

  • Anonymous
    November 06, 2008
    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 ...

  • Anonymous
    November 06, 2008
    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.  

  • Anonymous
    December 17, 2008
    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

  • Anonymous
    December 19, 2008
    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.

  • Anonymous
    January 15, 2009
    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.

  • Anonymous
    February 25, 2009
    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.

  • Anonymous
    April 05, 2009
    You know the drill.. raw, unedited, yet deep and useful WPF conversations !! Subject: Changing Resources

  • Anonymous
    April 10, 2009
    UPDATE: the WPF DataGrid v1 has just released. For more information, see this post . The information

  • Anonymous
    June 29, 2009
    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

  • Anonymous
    June 30, 2009
    Gaurav, You can set DataGrid.CanAddNewRow to false.

  • Anonymous
    July 15, 2009
    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!

  • Anonymous
    July 17, 2009
    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

  • Anonymous
    July 19, 2009
    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..

  • Anonymous
    July 20, 2009
    Mahender, This is a known bug that has been fixed in the dev10 timeframe.  Currently there isn't any easy workarounds.

  • Anonymous
    July 21, 2009
    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

  • Anonymous
    August 24, 2009
    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?

  • Anonymous
    September 08, 2009
    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.

  • Anonymous
    October 13, 2009
    The comment has been removed

  • Anonymous
    October 20, 2009
    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.

  • Anonymous
    November 22, 2009
    It seems that msdn is posting wrong content-type with the sample: The transferred file "http://blogs.msdn.com/vinsibal/attachment/9044516.ashx/DataGrid_V1_NewItemTemplate_Sample/DatabaseAccess/bin/Debug/DatabaseAccess.pdb" has been blocked by Webwasher, because the content of the file does not match the content type "application/palm-adrcty" and Webwasher can not correct it.

  • Anonymous
    March 09, 2010
    Hi Vincent, I have same problem as MartonSzabo, but your suggestion is right. I have public class Items: ObservableCollection<Item>, when items.Count == 0 and ItemsSource="{Binding items}" then show nothing, because Items derives from it ObservableCollection. Thank's!