WPF DataGrid - Event for New Rows?
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.
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
};
}
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.
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
.
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:
- 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 ifMyViewModel
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. - Now it waits until the user goes to edit the row, at which point it starts the add proper.
- 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. TheAddingNewItemEventArgs.NewItem
has a setter and you can swap the current item for your own.
I've found the DataGrid_InitializingNewItem event to be helpful where you can examine e.NewItem and take appropriate actions based on its type.
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.
Unlike AddingNewItem
, DataGrid.LoadingRow Event (available since .Net 4.0) will be fired for items added through ItemSource
binding.
精彩评论