Datagrid CanUserAddRows / Databinding issue

Dec 15, 2008 at 8:44 PM
I am having a confusing issue with the datagrid...

I have 2 controls... a datagrid and a combobox.  For sake of simplicity, let us say the items in the datagrid are of type Person.  If Person has Name and Age properties, then these are the columns of the datagrid.  CanUserAddRows on the datagrid is set to TRUE.

I have declared a variable Persons As ObservableCollection (of Person), which drives the itemssource for both the datagrid and the combobox.  The idea is that the user can edit the Persons collection via the grid, and in the combobox will be able to select one person.

Everything works fine, except that I am getting an empty item in the combobox (along with the person items from the persons collection).  It is NOT in the Persons collection, but only shows up in the combobox.  The empty item is not of the type Person either.

I have pretzeled my brain trying to figure this out... any help would be appreciated.

Dec 16, 2008 at 12:52 AM
I believe my question can be answered by someone explaining how WPF adds an item to a databound ObservableCollection.

if I have a datagrid, with ItemsSource databound to an observablecollection (of Person), and UserCanAddRows = TRUE...
and the user adds a new row on the datagrid, how does this new Person item get added to the ObservableCollection?

It does not seem to use the Add method on ObservableCollection... 
or at least it doesn't if I create a derivation of ObservableCollection and Shadow the Add method.

Dec 16, 2008 at 1:31 AM
After a little more digging, I have found that the empty item is of type {MS.Internal.NamedObject}

Setting CanUserAddRows to False fixes the problem, but as I need the functionality to have the user add rows I need a workaround.
Dec 18, 2008 at 8:42 PM
The DataGrid uses IECV to add additional items.  For more info on it see this post, and this post,
Dec 18, 2008 at 9:09 PM
Thanks vinsibal.

I'm still not understanding though... it seems like the empty item would need to be added before it actually manifests itself.  Meaning, that the user would have to at least click on the insertrow.

What I am seeing is a {MS.Internal.NamedObject} that somehow gets ported over databinding to another control.  If I have a setup like the following...

Datagrid <----> ObservableCollection(of Person) <-----> combobox

whereby the datagrid is twoway databound to the observable collection, and the combobox is one-way databound to the observable collection. 

The {MS.Internal.NamedObject} shows up in the combobox, but not in the observablecollection.  It is not of the type Person either.

Thanks for your help...
Dec 31, 2008 at 9:36 PM

I ran into this same thing. I found a work around. Altho I'm not sure it is the "right" way to solve the problem, it works:

Instead of binding to Persons directly with your two controls, bind to a new ListCollectionView(Persons) in each case. What I did was expose a property called View like this from my Persons object:

    Public ReadOnly Property View() As ListCollectionView
            Return New ListCollectionView(Me)
        End Get
    End Property

Then in my xaml, I bound to the View property of Persons instead of binding directly to persons.

What I surmise to be the issue is that if you don't specify a new ListCollection, then it uses the equivalent of CollectionViewSource.GetDefaultView(Persons) which returns the same default view to both the combo box and the datagrid. The datagrid apparently does something to that view (having to do with the NewItemPlaceHolder) which causes the new item placeholder to show up for the combo box as well.

At any rate, this is a work around that worked for me. If anyone else knows why this option is a bad idea, by all means, please post!

Dec 31, 2008 at 10:05 PM

thanks for the reply...  your fix certainly takes care of the empty item issue.   However, it seems to mess with the selection logic of the combobox itself.  This is not necessarily a killer if I can figure out why it's different.

I don't understand ListCollectionViews all that well.  Is this a normal application of a listCollectionView?  Namely, using it as an intermediate step for databinding to controls?

Dec 31, 2008 at 10:10 PM
Edited Dec 31, 2008 at 10:10 PM

Can you elaborate a little more on how it seems to mess with the selection logic of the combo box? There may be some side effect to this work-around that I haven't seen yet, so I'm interested to hear what you're seeing.

As for whether or not this is "normal" application of the ListCollectionView, I'm not sure. I'm no expert on these either. But my understanding is that a ListCollectionView is used behind the scenes as an "intermediate" for binding the ObservableCollection to the controls. The only difference here is that we're manually creating that LCV instead of letting it use the "default" ListCollectionView.

Like I say tho, I'm just learning this stuff myself, so my solution may not be optimum. Hopefully someone with more expertise will weigh in here.

Dec 31, 2008 at 10:21 PM
Well, my case is rather odd...  I use the same combobox around the whole application.  The combo I saw the selection logic changed is not actually one of the comboboxes that is databound (through the intermediate object) to the datagrid.

I have made my own class and style for ComboBoxItem, which utilizes a IsEnabled property.  This allows me to enable/disable options in the combobox by setting the IsEnabled property on my business object. 

Upon a change of other options in the window, I scroll through the observablecollection backing the combobox to see if each option is valid.  If not, I disable it.  During this procedure, If I enable a comboboxitem, it is now automatically selecting it as well (this is not correct behavior)... this only happens when I use your method of binding to the listcollectionview.

Like I said, it's a rather abstract change...

Dec 31, 2008 at 10:23 PM
Another strange change I noticed...  your fix seems to solve the problem I just posted about in another thread too...

Very odd.