ObservableCollection (again)

Posts   
 
    
yowl
User
Posts: 266
Joined: 11-Feb-2008
# Posted on: 09-Mar-2021 16:38:34   

Hi,

I want to bind in the UI to an ObservableCollection not an IBindingList. Mainly performance (https://stackoverflow.com/questions/4284663/difference-between-observablecollection-and-bindinglist) and from a functional point of view https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Data/BindingListCollectionView.cs,570

This setting of a new item in a grid situation where there is a master grid/detail section going on is a pain, because as soon as you start adding the new row (which may be cancelled), the SelectedItem changes and from that can flow a bunch of UI problems.

So I can see 2 options neither of which is very attractive and maybe you can suggest something else. If it's a lot of work, then that is not necessarily a blocker.

1 Use EntityFramework (rather not as I like LLBLGen runtime framework and the FastSerializer) 2 Edit LLBLGen source code (a horrible idea for keeping up with the latest versions)

Is there anything else I could do, can I somehow insert my own implementation of IListSource maybe?

Thanks for reading.

Scott

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 09-Mar-2021 21:49:01   

What kind of UI is this? WPF?

Which LBLGen runtime library version are you using?

yowl
User
Posts: 266
Joined: 11-Feb-2008
# Posted on: 09-Mar-2021 21:51:11   

Yes WPF with Telerik controls if relevant, LLBLGen 5.7

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 10-Mar-2021 10:46:34   

You didn't say what it is exactly that you're trying to do that fails, e.g. you bound an entity collection (thus an entity view) to a grid? Did you try that and that failed? For UI management we have implemented a DataScope class which does a lot of the management for you.

Frans Bouma | Lead developer LLBLGen Pro
yowl
User
Posts: 266
Joined: 11-Feb-2008
# Posted on: 10-Mar-2021 17:57:58   

I'm trying to bind to an EntityCollection, have an entity added and not change the CurrentItem. If you bind to an IBindingList, then the grid will create a BindingListCollectionView over the IBindingList. When the grid calls AddNew it will go through https://github.com/dotnet/wpf/blob/master/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingListCollectionView.cs#L590 and change the CurrentItem and hence the SelectedItem with this type of binding

        <telerik:RadGridView ItemsSource="{Binding TradeEntityCollection}" IsSynchronizedWithCurrentItem="True" CanUserInsertRows="True" NewRowPosition="Top" SelectedItem="{Binding SelectedTrade, Mode=TwoWay}"
                             AutoGenerateColumns="False" >
            <telerik:RadGridView.Columns>
                <telerik:GridViewDataColumn DataMemberBinding="{Binding TradeNumber}"></telerik:GridViewDataColumn>
            </telerik:RadGridView.Columns>
        </telerik:RadGridView>

This does not happen with ObservableCollection and the ObservableCollection is the behaviour I want. I do not want a change in SelectedItem (in the above binding) until the new row is committed to the grid (this is what you get with ObservableCollection). So it's not that it fails, so much as the IBindingList behaviour is less desirable than the ObservableCollection behaviour (for me at least).

Does the implementation of IListSource come from

<taskPreset name="SD.Tasks.Generic.EntityClassesGenerator" requiresCleanCache="false"> <parameters> <parameter name="destinationFolder" value="[dbgenericSubFolder]\EntityClasses" /> <parameter name="templateID" value="SD_EntityAdapterTemplate" /> </parameters> </taskPreset> ?

Thanks for the DataScope reference (looks similar to Ria Context).

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 11-Mar-2021 03:57:36   

I'm not sure about Telerik Grid, but I've tested this with the vanilla Data Grid control, and both EntityCollection and ObservableCollection have the same behaviour. Both fire the SelectionChanged event when inserting new item.

Do you see different behavior with the vanilla DataGrid? What about if you wrap the EntityCollection in an Observable one, before binding, would that work out with Telerik the way you want?

yowl
User
Posts: 266
Joined: 11-Feb-2008
# Posted on: 11-Mar-2021 14:07:10   

I did try DataGrid, but I couldn't see a way to get a new row out of it. The only way I could see how to do that with DataGrid was a button that added a row to the backing list. Ive never used Datagrid, so maybe I'm missing something. DevExpress and Telerik have a new row function built into the grid, which is what I want to use. I dont think I can post pictures to this forum otherwise I'd highlight that feature.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 11-Mar-2021 19:22:24   

In the vanilla Data, you get to see an empty row if you scroll down. Now you can edit it, and when you press enter or lose focus you should get the newly inserted data in the LostFocus event.

Or you can add the following to each column binding: UpdateSourceTrigger=PropertyChanged e.g.

<DataGridTextColumn Header="Total" Binding="{Binding CustomerId, UpdateSourceTrigger=PropertyChanged}" Width="120" />

This way you should get the new entity in the RowEditEnding event: e.Row.Item.

yowl
User
Posts: 266
Joined: 11-Feb-2008
# Posted on: 11-Mar-2021 19:40:48   

Agreed DataGrid does the same for both. Doesn't help me much as I'm not using it, but I concur with your observation.

yowl
User
Posts: 266
Joined: 11-Feb-2008
# Posted on: 11-Mar-2021 19:52:10   

I'll elaborate a little more on how bad DataGrid is and hence why its not a good reference, bind the SelectedIndex to

        int selectedIndex;
        public int SelectedIndex
        {
            get => selectedIndex;
            set
            {
                selectedIndex = value;
                Debug.WriteLine("Selected index changed to " + selectedIndex + " items in collection " + TradeEntityCollection.Count);
                OnPropertyChanged();
            }
        }

And in the output you will see when adding a new row

Selected index changed to 1 items in collection 1

Selected index changed to -1 items in collection 1

Selected index changed to 1 items in collection 2

The index goes to 1, when there is only one item (so index of 0 is the only valid value), then it goes to -1 (what does that mean), and finally it goes to 1 again after adding the item to the collection.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 12-Mar-2021 01:05:43   

As you start editing the first row, it's index is shown as selected (1 in your case). -1 means nothing is selected.

So back to your issue, it appears to me... it's a Telerik control specific. Could you please ask their support team why their control is not rendering the same behavior for IBindungList as in Observable Collection?

yowl
User
Posts: 266
Joined: 11-Feb-2008
# Posted on: 12-Mar-2021 01:22:57   

I did and they pointed me to https://github.com/dotnet/wpf/blob/master/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Data/BindingListCollectionView.cs#L590

ObservableCollection does not have that code.

But we are going in circles, so lets not waste any more of each others time and I'll just close this and I'll do my own thing. Thanks for looking.