Reputation: 10242
I am trying to prevent the user to add empty DataGrid
rows when using the built-in .NET DataGrid
AddNewItem-functionality. So when a user tries to commit an AddNew transaction of the DataGrid
and leaves PageItemViewModel.Text
empty, it should disappears from the DataGrid
.
ViewModels
public class PageItemViewModel
{
public string Text { get; set; }
}
public class PageViewModel
{
public ObservableCollection<PageItemViewModel> PageItems { get; } = new ObservableCollection<PageItemViewModel>();
}
View
<DataGrid AutoGenerateColumns="True"
CanUserAddRows="True"
ItemsSource="{Binding PageItems}" />
... removing the automatically created object from the DataGrid
's ItemsSource
while handling:
DataGrid.AddingNewItem
INotifyCollectionChanged.CollectionChanged
of PageViewModel.PageItems
IEditableCollectionView.CancelNew
DataGrid.OnItemsChanged
... but always receive exceptions like:
- "System.InvalidOperationException: 'Removing' is not allowed during an AddNew or EditItem transaction."
- "System.InvalidOperationException: Cannot change ObservableCollection during a CollectionChanged event."
- "System.InvalidOperationException: Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead."
How can I prevent the newly created PageItemViewModel
from being added to the
ObservableCollection<PageItemViewModel>
, when there is a given condition (in this case: String.IsNullOrWhiteSpace(PageItemViewModel.Text) == true
.
@picnic8: The AddingNewItem
event does not provide any form of RoutedEventArgs
and therefore no Handled
property. Instead, it is AddingNewItemEventArgs
. Your code is invalid.
private void DataGrid_AddingNewItem(object sender, AddingNewItemEventArgs e)
{
var viewModel = (PageItemViewModel)e.NewItem;
bool cancelAddingNewItem = String.IsNullOrWhiteSpace(viewModel.Text) == true;
// ??? How can i actually stop it from here?
}
Upvotes: 4
Views: 894
Reputation: 205619
You can't and shouldn't prevent adding to the underlying collection because when the end user starts typing in the new row, DataGrid
will create and add a new PageItemViewModel
object which at that time is initialized with default values.
What you can do though is to prevent committing that object by handling the DataGrid.RowEditEnding
event when DataGridRowEditEndingEventArgs.EditAction
is DataGridEditAction.Commit
and use DataGrid.CancelEdit
method to effectively remove the new object (or restore the existing object state) when the validation failed.
private void DataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
if (e.EditAction == DataGridEditAction.Commit)
{
var bindingGroup = e.Row.BindingGroup;
if (bindingGroup != null && bindingGroup.CommitEdit())
{
var item = (PageItemViewModel)e.Row.Item;
if (string.IsNullOrWhiteSpace(item.Text))
{
e.Cancel = true;
((DataGrid)sender).CancelEdit();
}
}
}
}
An important detail is that the RowEditEnding
event is fired before pushing the current editor value to the data source, so you need to do that by hand before performing the validation. I've used BindingGroup.CommitEdit
method for that.
Upvotes: 6
Reputation: 373
In your VM, subscribe to the AddingNewItem event and check your condition there. You can stop the action if the condition fails.
var datagrid.AddingNewItem += HandleOnAddingNewItem;
public void HandleOnAddingNewItem(object sender, RoutedEventArgs e)
{
if(myConditionIsTrue)
{
e.Handled = true; // This will stop the bubbling/tunneling of the event
}
}
Upvotes: -1