Search code examples
c#wpfbindingdatagridvalue-type

No Add Rows Operation allowed when a DataGrid binds to a list or observable collection of Double


I have an ObservableCollection<double> that is defined in my ViewModel.

ListWidthsFlat=new ObservableCollection<double>();
ListWidthsFlat.Add(120);
ListWidthsFlat.Add(200);

My XAML code :

<DataGrid ItemsSource="{Binding Path=ListWidthsFlat}" AutoGenerateColumns="False"
 CanUserAddRows="True" CanUserDeleteRows="True" HorizontalAlignment="Center">
    <DataGrid.Columns>
        <DataGridTextColumn Header="{x:Static p:Resources.Width}" Binding="{Binding ., UpdateSourceTrigger=PropertyChanged}" Width="100" />
    </DataGrid.Columns>
</DataGrid>

What I want is show the ObservableCollection, then offer possibility to add/delete items from my ObservableCollection<double>.

When I do the same thing on an ObservableCollection<T> all is working perfectly. But when binding to ObservableCollection<double>, seems that parameters CanUserAddRows is not working.

Edit :

After additional tests, it seems the problem is that when I bind a DataGrid to an ObservableCollection<T>, and set CanUserAddRow=True, an additional empty line is automatically created (so I can edit it and add a new item to ObservableCollection.

When I bind a DataGrid to ObservableCollection<double>, no empty line is created.

Here is a screenshot to make it more understandable :

enter image description here


Solution

  • To properly do a CanUserAddRows the object list being bound to must implement IEditableCollectionView Interface which provide basic editing capabilities to the collection being bound to. Within that the item being presented from the list has to have a public default parameterless constructor.

    Because a value type double does not have a constructor the grid detects that and does not provide an add row; hence you see the failure on double alone, but it works on the object, (class) instances of List<T> which have double as a specific property.


    To work around the limitation,

    1. Create a class which has a public parameterless constructor and one double property.
    2. Then create your list of class and bind to that ObservableCollection (or List works too actually if you don't need the overhead of the observablecollection.) with a set of your values.
    3. In Xaml set the column in the datagrid to point to the double property.
    4. You may need to write a value constructor which will take in a float and return a string, and convert a string to a float.