Chaining Binding Sources not possible?

Posts   
 
    
njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 26-Nov-2007 04:56:32   

Hi guys. I'm having trouble with Design Time Data binding and the EntityCollection objects from your framework. Let's consider the clasic example of Customers collection. Each customer entity in the collection has an Orders Collection. Each Order Entity has an Order Details Collection. So we have a 3 level hierarchy.

Great.

Let's do some simple data binding with WinForms using Visual Studio...

1) Drag and Drop LLBLGen "CustomersCollection" data source to a form. Name it "m_customersCollection" 2) Drag and Drop a .NET 2.0 BindingSource control to the form. Name it "m_customersBindingSource". 3) Set "DataSource" property on m_customersBindingSource to the m_customersCollection. 4) Drag and Drop another BindingSource control to the form. Name it "m_ordersBindingSource" 5) Set "DataSource" property on m_ordersBindingSource to m_customersBindingSource. 6) Set "DataMember" property on m_ordersBindingSoruce to "Orders" (The OrdersCollection was browsable, ya!) 7) Drag and Drop third and final BindingSoruce control to the form. Name it "m_orderDetailsBindingSource". 8 ) Set "DataSource" property on m_orderDetailsBindingSource to m_ordersBindingSource. 9) Set "DataMember" propery on m_orderDetailsBindingSource to "OrderDetails". Wait a minute!! There is nothing that I can select for DataMember. It's like "Browsability" was suddenly turned off or something?????????

This simple example of chaining binding sources is supposed to work for N levels. Microsoft provides many examples of this using their Typed Data Sets or custom objects.

Why does this not work with LLBLGen Pro?

It seems to me that I will be forced to set binding at runtime programatically for all forms where we are presenting a hierarchy of 3 levels or more. Maintaining this type of code behind each form will be troublesome. I have many forms that have hierarchies going 4-5-6-7 levels deep.

HELP! We are still in eval stage with your product but this is a major set back in my opinion. Everything else is fantastic.

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 26-Nov-2007 11:08:01   

Reproduced, I couldn't do it in design time, and the I could only do it in code as follows:

        private void dataGridView2_CurrentCellChanged(object sender, EventArgs e)
        {
            int customerIndex = (dataGridView1.SelectedRows.Count > 0)?dataGridView1.SelectedRows[0].Index : 0;
            int orderIndex = (dataGridView2.SelectedRows.Count > 0)?dataGridView2.SelectedRows[0].Index : 0;

            //bindingSource3.DataSource = customersCollection1[customerIndex].Orders[orderIndex].OrderDetails;
            //dataGridView3.DataSource = bindingSource3;
            dataGridView3.DataSource = customersCollection1[customerIndex].Orders[orderIndex].OrderDetails; 
        }

Either by using a BindingSource or not. (check the commented code) Either way don't set the dataGridView3.DataSource at design time.

We will further investigate this.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 26-Nov-2007 12:00:54   

This is turned off, because vs.net will otherwise dive into an infinite loop. The reason is m:n relations. These create cycles in graphs with collections so both sides get their ITypedList implementation called. This goes wrong. Trust me, I've spend weeks on this problem, implemented property descriptor caches to return the same descriptors to make it think it has already seen the element... no dice, it hangs.

You can't compare it to datasets, as datasets use datarelation objects, and the controls are often using these directly (as datatables are bound via DataViews which don't have relations at all), with custom code paths, so these use different code than normal object hierarchies.

Added to that: a 3-level bind isn't supported anyway. What you're doing is just sugar: under the hood this happens: - the currency manager of the form is the controller of the binding. Nothing else controls it, the currency manager does - what you set up, is the same as: master, detail, superdetail: in 3 grids you bind to all grids the same customers collection. In the detail grid you specify 'Orders' as datamember and for superdetail you specify ... yes, what do you specify? simple_smile

You can't do: "Orders[x].OrderDetails", that's not accepted by .NET. Neither is: "Orders.OrderDetails". So the currency manager can't deal with this properly: it can't keep all sets in sync as it requires for that the same set is bound to all grids.

There are grids which offer multi-band databinding. These handle the syncing themselves, not the currency manager on the form.

Frans Bouma | Lead developer LLBLGen Pro
njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 26-Nov-2007 15:07:35   

Ok. So it is a limitation of LLBLGen Pro for the supported data binding scenario. I kinda see why you stop at two levels. What datagrids are you refering to that support "multi-band data binding"?

Thanks

njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 26-Nov-2007 15:14:52   

Reading your post again. I think you are a little off as I'm reading a .NET 2.0 Data Binding book and it explicitly shows examples of "Chaining Binding Sources" for a three level hierarchy. They do not specify an EntityCollection.Entity in the DataMember property.

Anyhow. I understand your dilemna with many to many relations and the possibility of infinite loops.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 26-Nov-2007 15:50:53   

njetty wrote:

Ok. So it is a limitation of LLBLGen Pro for the supported data binding scenario. I kinda see why you stop at two levels. What datagrids are you refering to that support "multi-band data binding"? Thanks

I don't know IF it is caused by the limit build in but I think it's very likely: there's just 1 level of related elements reported, not multiple levels. With custom classes this goes OK, however when you implement ITypedList, it goes wrong. So when vs.net does the reflection by itself it works, you don't get infinite loops, but when you implement ITypedList, like we do, you do get infinite loops. Perhaps they've fixed it in SP1 for vs.net 2005, I've to check, but I doubt it.

Grids which support multi-banding are for example DevExpress' grid or Janus grid.

In a way it is surprising though that it doesn't work, because you'd think that the types returned will be the root of a new level of related elements if you chain a new bindingsource to it.

I'll try to check with the debugger attached to the collection code what happens at design time and if we're still getting lockups with multi-level element returns.

Frans Bouma | Lead developer LLBLGen Pro
njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 26-Nov-2007 16:31:09   

Thanks for the quick response and offer to take another look. Chaining multiple Binding Sources would save me...

1) Looking at aftermarket controls 2) Implementing run time code behind every form that has a hierarchy of 3 or more. Having to set data source property on all child Binding Sources at run time is a pain. (i.e. implementing event handlers on parent binding source to rebind all child sources when current row has changed).

I'm sure there are other users interested in this design time support.

P.S. The data binding support for your collection entities is top notch. I've run into zero issues with 1 or 2 level hierarchy scenarios. Very seemless and works flawlessly.

Thanks Again!

njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 26-Nov-2007 16:42:03   

Just another thought and I know this could be alot of work for you....

Instead of stopping the "browsability" at say two levels. Why not have it at a higher number like 5 or 6 (maybe user definable in code generation phase)? Would this not short circuit infinite loops while also providing design time data binding support at levels that most users will not need to go beyond?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 26-Nov-2007 17:23:27   

njetty wrote:

Just another thought and I know this could be alot of work for you....

Instead of stopping the "browsability" at say two levels. Why not have it at a higher number like 5 or 6 (maybe user definable in code generation phase)? Would this not short circuit infinite loops while also providing design time data binding support at levels that most users will not need to go beyond?

That's not detectable, unfortunately... So it simply chops off related entity collections in the set of related elements during design mode.

I'll check if the bug is still present in vs.net. If not I'll flip the switch for design time databinding as well(it should work at runtime btw)

Thanks for your kind words simple_smile

Frans Bouma | Lead developer LLBLGen Pro
njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 26-Nov-2007 18:39:44   

Note for others out there...

From Frans' last post I found out that I could do "Chaining of Binding Sources" within the OnFormLoad Event handler rather than using the parent binding source OnCurrentChanged Event handler. The first approach is much better as we are not having to "rebind" when the user navigates from parent to parent.

I'm hoping we can set this up at design time in the future but for now, this is the best approach.

Example...

    private void BorrowersForm_Load(object sender, EventArgs e)
    {
        //LLBLGen does not support Design Time Chaining Binding Sources
        //We must set this up now...

        //Loans...
        this.loansBindingSource.DataSource = this.borrowerBindingSource;
        this.loansBindingSource.DataMember = "Loans";

        //Loan Comments....
        this.loanCommentsBindingSource.DataSource = this.loansBindingSource;
        this.loanCommentsBindingSource.DataMember = "LoanComments";

        //Loan Expenses....
        this.loanExpensesBindingSource.DataSource = this.loansBindingSource;
        this.loanExpensesBindingSource.DataMember = "LoanExpenses";

        //Loan Revenue At Closing...
        this.loanRevenuesAtClosingBindingSource.DataSource = this.loansBindingSource;
        this.loanRevenuesAtClosingBindingSource.DataMember = "LoanRevenueAtClosings";

        //Loan Revenue After Closing...
        this.loanRevenuesAfterClosingBindingSource.DataSource = this.loansBindingSource;
        this.loanRevenuesAfterClosingBindingSource.DataMember = "LoanRevenueAfterClosings";

        //Loan Holdbacks...
        this.loanHoldbacksBindingSource.DataSource = this.loansBindingSource;
        this.loanHoldbacksBindingSource.DataMember = "LoanHoldbacks";

    }
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 27-Nov-2007 14:24:41   

Well, good news simple_smile . I have switched off the limiter and vs.net doesn't dive into an infinite loop anymore. It still shows a single level of related elements, which is OK, and your chaining example indeed now works: I can select the orderdetails collection as datamember.

At runtime this then also works: 1 line of code needed: to fetch the initial customers.

I'll patch the 2.5 runtime for .net 2.0+ and will attach a new build to this post, so you can check it out.

Edit: attached. (build 11272007).

Frans Bouma | Lead developer LLBLGen Pro
njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 07-Dec-2007 05:30:59   

I finally got around to testing this today. Unfortunately something is messed up. You can definitely chain data sources as described at design time. The problem is when you associate DataGridView Controls to the "3rd and 4th level" binding sources. All Data Grid Views bound only present "Columns" pertaining to one of the "3rd and 4th level" binding sources. I tried everything.

Can you reproduce on your end?

I'll have to revert back for now.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39908
Joined: 17-Aug-2003
# Posted on: 07-Dec-2007 12:52:52   

So if you have customers - orders - order details, and you assign a grid to the datasource which represents order details, all grids show columns of order details? I was able to design a 3-layer form with customers, orders and order details in design view and at runtime, completely working without 1 line of code.

Frans Bouma | Lead developer LLBLGen Pro
njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 07-Dec-2007 15:32:20   

Try customers, orders, order details (3rd level), order notes (3rd level), order detail notes(4th level).

I would get one of the 3rd level grid views working just fine as you have. But strangely other 3rd level/4th level grid views although bound to different data sources would only present columns (in designer) for the working 3rd level binding source.

I will try to reproduce again tonight. This time on an entirely new form. I was working with an existing form last night. I tried everything to get it working but had to revert back for now.

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 10-Dec-2007 11:26:40   

Unfortunatly (or fortunatly simple_smile ), I could't reproduce it. I've downloaded and used the latest RTL build (29 Nov). And I created 4 levels of GridViews with binding Sources with more than one Grid/Collection displayed in Each Level, and everything worked perfectly as expected.

I will try to reproduce again tonight. This time on an entirely new form. I was working with an existing form last night. I tried everything to get it working but had to revert back for now.

Did you succeed in reproducing it?

njetty
User
Posts: 12
Joined: 22-Nov-2007
# Posted on: 15-Jan-2008 04:21:29   

I've recently built a new form with the binding sources 3 levels deep and things appear to be working. I'll continue to experiment and possibly go back to my original complex form to see if it can be reworked.

tangent
User
Posts: 41
Joined: 30-Apr-2006
# Posted on: 15-Jan-2008 08:22:51   

Another thing you could try is this.. bindingsource component modified to support heirarchy and using dynamic IL instead of standard reflection, it works great =)

http://www.codeproject.com/KB/cs/ObjectBindingSource.aspx

There is also a project on codeplex called genius binding which has some good databinding bits.

For what it is worth my personal opinion is that in the long run it is better to not use design time databinding but develop a clean way of doing it programmatically. Just ask yourself this: how many times have you wasted time debugging and then figured out some binding was set incorrectly in the designer?

In a larger project design time binding can become maintenance nightmare, it is much easier to spot these problems when the binding code is right in front of your face instead of abstracted away by the designer.