I'm developing a WPF application (using .NET 4.5), part of which involves showing some data in a DataGrid.
The user has the ability to add a new row inside the DataGrid and delete one via a button elsewhere.
I have an issue when the user starts adding a new row that cannot be committed and then presses the delete button.
The new row should be canceled and the DataGrid reset to its previous state.
However, the DataGrid's NewItemPlaceholder
row is deleted and never shown again.
I've made a sample project that demonstrates the issue.
Here is a short screencast as well.
This is what the sample app looks like.
To reproduce:
The viewmodel gets the data in an ObservableCollection, which is used as the source for a collection view.
I have a simple command wired to the delete button. If the user is adding an item (IEditableCollectionView.IsAddingNew
) I try to cancel the operation using .CancelNew()
on the collectionView. However, when the command completes the DataGrid has its NewItemPlaceholder
deleted.
So far, I've tried:
dataGrid.CanUserAddRows = true
, which fixes the issue somewhat, but that's a horrible workaround and it's buggy, afterwards the placeholder is not editable.this.productsObservable.Remove(this.Products.CurrentAddItem as Product)
.this.Products.Remove(this.Products.CurrentAddItem)
.'Remove' is not allowed during an AddNew or EditItem transaction.
Is there another way I can cancel the user's add AND have the NewItemPlaceholder showing?
In the sample project I'm instantiating the data inside the VM constructor for simplicity.
In reality I'm using async calls to a service, wrapping the result in ObservableCollection and the ViewModel implements INotifyPropertyChanged. The business object doesn't implement INPC.
XAML for the sample project:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication3"
Title="MainWindow" Height="250">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<StackPanel Orientation="Vertical">
<Button Command="{Binding DeleteCommand}" Content="Delete row" />
<DataGrid
ItemsSource="{Binding Products}"
CanUserDeleteRows="False"
CanUserAddRows="True"
SelectionMode="Single">
</DataGrid>
</StackPanel>
</Window>
ViewModel, together with a simple Business Object:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Data;
using System.Windows.Input;
namespace WpfApplication3
{
public class ViewModel
{
private readonly ObservableCollection<Product> productsObservable;
public ViewModel()
{
this.productsObservable = new ObservableCollection<Product>()
{
new Product() { Name = "White chocolate", Price = 1},
new Product() { Name = "Black chocolate", Price = 2},
new Product() { Name = "Hot chocolate", Price = 3},
};
this.Products = CollectionViewSource.GetDefaultView(this.productsObservable) as IEditableCollectionView;
this.Products.NewItemPlaceholderPosition = NewItemPlaceholderPosition.AtBeginning;
this.DeleteCommand = new DelegateCommand(this.OnDeleteCommandExecuted);
}
public ICommand DeleteCommand { get; private set; }
public IEditableCollectionView Products { get; private set; }
private void OnDeleteCommandExecuted()
{
if (this.Products.IsAddingNew)
{
this.Products.CancelNew();
}
}
}
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
}
What about this:
private void OnDeleteCommandExecuted()
{
if (this.Products.IsAddingNew)
{
this.Products.CancelNew();
this.Products.AddNew();
}
}
You'll still delete the row with the bad input, but you'll add a new (mostly) empty row. The only problem, although I'm sure its fixable, is that you get the default 0
value in the numerical column not a null
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With