StrataFrame Forum

Business Binding Source

http://forum.strataframe.net/Topic11801.aspx

By Paul Chase - 10/2/2007

I have a Biz object (Biz Obj A) that contains a public property that is another biz obj (Biz obj B).

Both Biz obj A and B are same form and the property on A is pointing to B, Biz Obj A is also the Biz obj in a Bus Binding source that is the data source for a Data Entry Grid.

Biz object A raises and handles a value changed event for one of the fields in the grid. In the handled code it does some calculation and then try's to update some values on biz obj B. 

It appears the BBS is creating a new instance of biz obj A so that when Biz Obj A handles the value changed event it is actually being handled by a new instance of A that the Bus binding source creates and thus doesnt "know" about B.

I have just started trying to think of the best way to handle this.. any ideas?

Thanks

Paul

By Paul Chase - 10/3/2007

Okay here is another way to look at the same problem.

I have business object (A)

A has an Event called wishiworked that is raised when some field's value is changed.

I drop A onto a form

I drop a business binding source and set the bus obj property to A

I drop a grid and wire it up to the BBS.

I change the value of the field that the raises the wishiworked event. but because the event is raised in a new instance my form code below will not work.

I have the following code in the form.

Private sub youwillneverwork(By Val whatever event args I want) handles businessobjectA.wishiworked

msgbox("This will never fire from the Business Binding Source!!!!!!!")

end sub

Maybe that makes a bit more sense>?

By StrataFrame Team - 10/3/2007

Yes, that does make sense, and yes, the BBS does create a new instance of the BO for each record that is returned (pointed to the correct record).  So, the way you're going to have to handle this would be to add a handler to the business object's CurrentView.ListChanged event.  So, when the CurrentDataTable on the business object is filled, add a handler from the form to your business object's CurrentView.ListChanged event (since the CurrentDataTable is shared by all of those instances of the business object that are returned from the BBS), and in the event handler, if the event args indicate that it's an ItemChanged event, then call your logic.  But, the CurrentView.ListChanged is going to be the central place to handle that sort of logic; meaning that you can turn off the field changed events on the BO if this is all you're using them for.
By Paul Chase - 10/3/2007

Ben,

Maybe I'm missing something, but the event doesn't seem to get raised either.

 

AddHandler Me.CurrentView.ListChanged, AddressOf TestListChanged

Private Sub TestListChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ListChangedEventArgs)

Diagnostics.Debug.WriteLine(e.ListChangedType.ToString)

End Sub

 

By Paul Chase - 10/4/2007

Ben,

I think my head is about to explode. Who thought handling one event could cause this much trouble. The seas are too rough to fish and it is to hot to sit in a treestand so I guess I'm stuck trying to get this to work Angry

Any ideas you might have on how to make this work would be great

By Paul Chase - 10/4/2007

Here is a sample\test app that uses the Strataframe sample data with the bo mapped to the customers table, the event generation in bo mapper is set up as follows. As you can see the event will not get handled in the grid

By StrataFrame Team - 10/5/2007

The CurrentView.ListChanged event is the one that you want, but here's the deal... the CurrentView reference changes each time you refill the business object.  So, in the sample you gave me, you're adding the event handler too soon (before you fill the object), so it's not being added to the right view.  Add a handler to the business object's CurrentDataTableRefilled event and add the handler in there.  That way, each time you refill the business object, you'll get the handler added to the new view.  You also might want to save off a reference to the view so you can remove the handler from the old view before adding the new one.

Dim _CurrentView As DataView

Private Sub BusinessObject1_CurrentDataTableRefilled()
    If Me._CurrentView IsNot Nothing Then RemoveHandler Me._CurrentView.ListChanged, AddressOf TestListChanged
    Me._CurrentView = Me.BusinessObject1.CurrentView
    AddHandler Me._CurrentView.ListChanged, AddressOf TestListChanged
End Sub

By Paul Chase - 10/5/2007

Thanks Ben that makes sense. I will try to test it out today, thanks
By Paul Chase - 10/16/2007

Hi Ben,

The solution you suggested works however it still leaves me with a problem, Any property values that are set in the first BO are gone in the new instance that the business binding source creates.

for example I have a property that references another bus obj,

<Category("Action Labor : Related Business Objects"), _

DescriptionAttribute("Check Detail Business Object")> _

Public Property CheckDetailBiz() As Payroll.Business.BoCheckDetail

Get

If _CheckDetail Is Nothing Then

'Do not create a new instance!!!

End If

Return _CheckDetail

End Get

Set(ByVal value As Payroll.Business.BoCheckDetail)

_CheckDetail = value

End Set

End Property

 

I have a custom Bindable Property

''' <summary>

''' Total Deductions

''' </summary>

''' <remarks></remarks>

<Browsable(False), _

BusinessFieldDisplayInEditor(), _

Description("TotalDeductions"), _

DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _

Public ReadOnly Property [TotalDeductions]() As System.Decimal

Get

Return Me.GetTotalDeductions

End Get

End Property

Protected Overrides Function GetCustomBindablePropertyDescriptors() As MicroFour.StrataFrame.Business.FieldPropertyDescriptor()

Return New MicroFour.StrataFrame.Business.FieldPropertyDescriptor() { _

New MicroFour.StrataFrame.Business.ReflectionPropertyDescriptor( _

"WeekToDateEmployeeHours", GetType(BOWoLineItem)), _

New MicroFour.StrataFrame.Business.ReflectionPropertyDescriptor( _

"WeekToDateCustomerHours", GetType(BOWoLineItem)), _

New MicroFour.StrataFrame.Business.ReflectionPropertyDescriptor( _

"WorkWeek", GetType(BOWoLineItem)), _

New MicroFour.StrataFrame.Business.ReflectionPropertyDescriptor( _

"TotalDeductions", GetType(BOWoLineItem)) _

}

End Function

and finally the function

Private Function GetTotalDeductions() As Decimal

' Sum Deductions in checkdetail

Dim lnRetVal As Decimal

This will crash becuase checkdetailbiz is nothing in the spawned instance created by the BBS.

lnRetVal = CType(Me.CheckDetailBiz.CurrentDataTable.Compute("sum(cki_amount)", "cki_codetype = 21"), Decimal)

Return lnRetVal

End Function

This is a pretty big problem for me because I have quite a bit of business logic similar to this that is used in various parts of the application and it all works fine except when bound to a BBS.

Hope that makes sense.

Paul

By StrataFrame Team - 10/16/2007

I have to guess that the properties that field values you're setting should be unique for each row in the business object, right?  Like each row in the business object should have its own _CheckDetail...

There are 2 ways to accomplish that:

1)  When you add a handler to the list changed on the data table, add a new column to the data table that stores types of Object:

Me.CurrentDataTable.Columns.Add(New DataColumn("_CheckDetail", GetType(Object)))

This will allow you to store the _CheckDetail business object within the row that is using it.  So, each instance used by the BBS points to the correct _CheckDetail instance (obviously, you change your property to return Me.CurrentRow("_CheckDetail") and set it).

2)  The other option would be to created a shared property called _CheckDetails that is a dictionary of BoCheckDetail:

Private Shared _CheckDetails As New Dictionary(Of Integer, BoCheckDetail)

You would store all of the check detail business objects in the dictionary and access them by the PK of the current record.  This option would be secondary to the first since you would need to remember to clean out the dictionary when you're done because it's shared, so the garbage collector would never clean up the items in it unless you explicitly removed them.