I have read all the Q&A I could find here and on the MS forums about this exception, and tried most of the suggestions that I understood, and a few others. It seems that this exception can come up for a wide range of causes.
As with others, I have a WPF DataGrid bound to a collection, which throws this exception when one tries to edit one of the cells. They are set to be write-able, the collection is an ObservableCollection, I've implemented get and set handlers which send notification messages.
The suggestions I haven't tried are the ones involving implementing IList's non-generic interface, because I have no idea what I would do to do that. Also, I have many DataGrids bound to various lists and collections in my app which work, and this one used to work when it was bound to a LINQ collection.
Please help me figure out what I need to do here.
The Data Grid is:
<DataGrid Name="dgIngredients" Margin="567,32,0,44" Width="360" ItemsSource="{Binding}" IsReadOnly="False"
AutoGenerateColumns="False" HorizontalAlignment="Left" CanUserAddRows="False" CanUserDeleteRows="False">
<DataGrid.Columns>
<DataGridTextColumn Width="63" Header="Percent" Binding="{Binding Preference}" IsReadOnly="False" />
<DataGridTextColumn SortDirection="Descending" Width="301" Header="Ingredient" Binding="{Binding Ingredient}" IsReadOnly="True" CanUserSort="True" CanUserReorder="False" />
</DataGrid.Columns>
</DataGrid>
The column being edited is the non-read-only one, Preference.
The collection is:
private ObservableCollection<RAM_Ingredient> MemberIngredientPrefs = new ObservableCollection<RAM_Ingredient>();
The binding is:
dgIngredients.DataContext = MemberIngredientPrefs.OrderBy("Ingredient",true);
RAM_Ingredient is:
public class RAM_Ingredient : INotifyPropertyChanged
etc.
Where RAM_Ingredient.Preference is:
private int _Preference;
public int Preference
{
get
{
return _Preference;
}
set
{
// This is needed to send notification of changes (and to not throw an exception on grid edit!):
if ((_Preference != value))
{
SendPropertyChanging();
_Preference = value;
SendPropertyChanged("Preference");
}
}
}
The exception is:
System.InvalidOperationException was unhandled
Message='EditItem' is not allowed for this view.
Source=PresentationFramework
StackTrace:
at System.Windows.Controls.ItemCollection.System.ComponentModel.IEditableCollectionView.EditItem(Object item)
at System.Windows.Controls.DataGrid.EditRowItem(Object rowItem)
at System.Windows.Controls.DataGrid.OnExecutedBeginEdit(ExecutedRoutedEventArgs e)
etc...
I still don't know what specifically caused the problem, but I managed to work around it, and I'm not sure how much of what I did was overkill, but it works.
I created a new class just for the purpose of holding the data in the DataGrid rows. I make a List of objects of this class and fill it in and bind it to the DataGrid as I was doing before. I also added the usual stuff and nonsense for getting Change Notification to work (probably overkill) and I had to re-define a comparison function in a different way to get it to sort because of that whole comedy situation.
i.e.
...
The model class needs to implement the interface
INotifyPropertyChanged
coming from the namespaceSystem.ComponentModel
.Class example:
I have also this problem, And found that the point here is that we can not edit a IEnumerable in a DataGrid, only a list can be edited.
therefore we didn't need to create a new class, its works also on a LINQ query with anonymous return type. it's need only to be a list.
here is a sample of my code:
I had this same problem trying to create a list of rows from a join; since the LINQ query returns an IEnumerable, I had the DataGrid bound to that IEnumerable; this worked fine for readonly and oddly worked with ComboBoxes and some other custom controls I used, but plain text editing threw the InvalidOperationException. The solution was an ObservableCollection in place of the IEnumerable; basically from:
BoundView = (/*LINQ QUERY*/); // is IEnumerable<CustomJoinObject>
to
BoundView = new ObservableCollection<CustomJoinObject>(/*LINQ QUERY*/);
In both cases BoundView is the DataContext for the DataGrid.
I'm assuming this happens because IEnumerable doesn't have the machinery to support a datagrid, whereas ObservableCollection does.