13

I'm using the WPF DataGrid (.Net 3.5 SP 1 version from the Toolkit)

What event can I subscribe to, to detect when a new row is added? (e.g. when the user moves the cursor down or presses Enter a new blank row gets added to the grid).

Eventually what I want to do is use that event to calculate some default values and put them in the new row.

The grid is bound to a DataTable, if that makes any difference.

amiry jd
  • 27,021
  • 30
  • 116
  • 215
codeulike
  • 22,514
  • 29
  • 120
  • 167

7 Answers7

15

The event you are looking for is DataGrid.AddingNewItem event. This event will allow you to configure the new object as you want it and then apply it to the NewItem property of the AddingNewItemEventArgs.

XAML:

<DataGrid Name="GrdBallPenetrations"
      ItemsSource="{Binding BallPenetrationCollection}" 
      SelectedItem="{Binding CurrentSelectedBallPenetration}"
      AutoGenerateColumns="False" 
      IsReadOnly="False"
      CanUserAddRows="True"
      CanUserDeleteRows="True"
      IsSynchronizedWithCurrentItem="True"
      AddingNewItem="GrdBallPenetrations_AddingNewItem">

Code behind in C#:

private void GrdBallPenetrations_AddingNewItem(object sender,
    AddingNewItemEventArgs e)
{
    e.NewItem = new BallPenetration
    {
        Id              = Guid.NewGuid(),
        CarriageWay     = CariageWayType.Plus,
        LaneNo          = 1,
        Position        = Positions.BetweenWheelTracks
    };
}
Toni
  • 1,555
  • 4
  • 15
  • 23
dayneo
  • 482
  • 5
  • 12
  • 3
    I just figured I'd mention that this isn't available until .Net 4.5, for those still using older versions of the .Net framework. – SQLServerSteve May 17 '18 at 04:15
  • 2
    The `AddingNewItem` event does not fire if the items are added through `ItemsSource` binding. – wondra Jun 04 '19 at 12:28
  • @wondra, correct. The event only fires based on user input interactions with the grid. This is the best place to initialize a new data instance based on user interaction with the grid. From the perspective of the grid, any change you make to ItemsSource is a change coming from your data store and not from the user. Trying to manipulate ItemsSource for the purpose of initializing the new object will break the user interaction with the grid. – dayneo Jun 06 '19 at 08:27
10

Objects are persisted (inserted or updated) when the user leaves a row that he was editing. Moving to another cell in the same row updates the corresponding property through data binding, but doesn't signal the Model (or the Data Access Layer) yet. The only useful event is DataGrid.RowEditEnding. This is fired just before committing the modified row.

XAML

<DataGrid ... 
          RowEditEnding="MyDataGrid_RowEditEnding">
</DataGrid>

Code Behind

private void MyDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e) 
{    // Only act on Commit
    if (e.EditAction == DataGridEditAction.Commit)
    {
         var newItem = e.Row.DataContext as MyDataboundType;
         if (newItem is NOT in my bound collection) ... handle insertion...
    } 
}

All credits for this solution go to Diederik Krolls (Original Post). My respect.

highboi
  • 673
  • 7
  • 28
Califf
  • 504
  • 6
  • 17
8

Instead of working on events within your View (the grid), I'd recommend watching the bound object instead, and putting your logic there. This keeps your business logic with your business objects.

Since you're bound to a DataTable, the simplest way is to just subscribe to DataTable.TableNewRow.

amiry jd
  • 27,021
  • 30
  • 116
  • 215
Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 3
    I totally agree. This will give you a lot more flexibility. For example, someday in the future you may want a custom way to add a new row instead of using the datagrid. In this case, everything will already be in place because you only care that a new object was added to your collection... you could care less how it was added. – ChrisNel52 Jan 06 '11 at 17:46
  • 1
    I had looked at the DataTable RowChanged event but it wasn't firing at the right point for me. But the TableNewRow event does fire at the right time (when the new row is generated). Thanks. – codeulike Jan 07 '11 at 10:47
  • In scenario like a custom behavior this remark is useless. Currently creating a behavior that highlight rows with same values (for a given column) as selected ones, I don't want to attach the Item source on every rows. – Orace Jun 18 '20 at 10:20
4

I'm adding this because I've just spent close to 2 hours trying to work out how to get the DataGrid to add a new row when you are bound to a collection of view models and you need to control the construction of those view models.

So the setup is that you have an ObservableCollection<MyViewModel> that is bound to the ItemsSource of your DataGrid. You need to create MyViewModel yourself in the view model layer.

This is how the DataGrid appears to function when it adds a row automatically:

  1. When it creates that blank row at the bottom it creates a new instance of MyViewModel it will bind to the row by calling the default constructor on the type. Who knows why it does this, but if MyViewModel does not have a default constructor it will just fail to show that blank row. This is probably the place that you are stuck, because you don't have a default constructor, because you need to create the object yourself. Unfortunately you are going to need to go and add one. Again note that if the element type is an interface this is doomed to failure. The element type of the collection must be a concrete class with a default constructor.
  2. Now it waits until the user goes to edit the row, at which point it starts the add proper.
  3. It raises the AddingNewItem: this is where you can intercept the add operation and switch out the default constructor created instance it has created with your own instance. The AddingNewItemEventArgs.NewItem has a setter and you can swap the current item for your own.
satnhak
  • 9,407
  • 5
  • 63
  • 81
2

I've found the DataGrid_InitializingNewItem event to be helpful where you can examine e.NewItem and take appropriate actions based on its type.

Doug Dekker
  • 353
  • 2
  • 9
1

Unlike AddingNewItem, DataGrid.LoadingRow Event (available since .Net 4.0) will be fired for items added through ItemSource binding.

Orace
  • 7,822
  • 30
  • 45
1

In you XAML, include the following code in your Window tag:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmd="http://www.galasoft.ch/mvvmlight"

Next, inside you DataGrid element, add the following trigger:

<DataGrid ...>

  <i:Interaction.Triggers>
        <i:EventTrigger EventName="LoadingRow">
               <cmd:EventToCommand Command="{Binding LoadRowHandler}" 
                                                PassEventArgsToCommand="True"/>
         </i:EventTrigger>                        
   </i:Interaction.Triggers>

</DataGrid>

Next, in you View Model, add a command for handling the event :

public RelayCommand<DataGridRowEventArgs> LoadRowHandler{ get; private set; }

Inside constructor, initialize the command:

LoadRowHandler = new RelayCommand<DataGridRowEventArgs>(LoadingRowHandlerMethod);

Next, create a method where you want to put the logic:

private void LoadingRowHandlerMethod(DataGridRowEventArgs e)
{
  //....
  //....
}

That's all. Now whenever a new row is added to your DataGrid, the LoadingRowHandlerMethod will get executed.

Hope it helps.

faiz-e
  • 190
  • 4
  • 21