Why the BO instance doesn't have the BO updated properties that was triggered by ValidateChildren()

Why the BO instance doesn't have the BO updated properties that was triggered by ValidateChildren()

Old forum URL: forums.lhotka.net/forums/t/3338.aspx


yimiqi posted on Monday, August 06, 2007

 I'm running into issues passing the user inputs into the Criteria object's constructor and exposed as a property of the Criteria for use in the DP_Fetch() method.  Basically the issue is the user inputs are not passed even if the property of the ERO are set to the input values.

I called ValidateChildren () to set the properties of the ERO,but the ERO I passed to the Criteria is empty or only has initial values.

I did:

Private mSearchInput As New SearchInput

Private Sub Search_Click() Handles cmdSearch.Click

Me.ValidateChildren()

Me.SearchInputBindingSource.DataSource =  objList.GetObjList(mSearchInput)

End Sub

The properities of the ERO has user inputs but mSearchInput doesn't, what did I miss?

Thanks in advance.

JoeFallon1 replied on Tuesday, August 07, 2007

Below is a sample class I built for a search screen for account codes.The idea is that each control on the screen will be bound to the BO. So I have checkboxes on the left side and then dropdowns and textboxes for each field (acctcode, acctdesc, etc.)

When the user clicks search the screen is unbound into the BO and then the BO is passed to another BO as a parameter to its Fetch method. This way the Fetch method "knows" exactly what the user selected on the search screen.

The factory method of an ROC that returns the list of Accts the user is searching for looks like this:

Public Shared Function GetAcctList(ByVal AcctSearchCriteriaBO As AcctSearchCriteriaBO) As AcctList
 
Return DataPortal.Fetch(Of AcctList)(New SearchCriteria(AcctSearchCriteriaBO))
End Function

The embedded Criteria class (there is more than 1) is given a new name of SearchCriteria and looks like this:

<Serializable()> _
Private Class SearchCriteria
 
Public AcctSearchCriteriaBO As AcctSearchCriteriaBO
 
  Public
Sub New(ByVal AcctSearchCriteriaBO As AcctSearchCriteriaBO)
   
Me.AcctSearchCriteriaBO = AcctSearchCriteriaBO
 
End Sub
End Class

Then the Fetch code is like this:

Protected Overrides Sub DataPortal_Fetch(ByVal criteria As Object)
  RaiseListChangedEvents =
False
 
IsReadOnly = False

  Dim dr As SafeDataReader = Nothing
  Dim strSQL As String = ""
  Dim crit As SearchCriteria = CType(criteria, SearchCriteria)
  strSQL = GetSQL(crit.AcctSearchCriteriaBO)

  dr = New SafeDataReader(DAL.ExecuteReader(strSQL))

 While dr.Read
   
Dim info As New AcctInfo(dr)
   
Me.Add(info)
 
End While

  IsReadOnly = True
  RaiseListChangedEvents = True
End Sub

Private Function GetSQL(ByVal mCrit As AcctSearchCriteriaBO) As String

  'use the checked properties only to include in the Search

  'build a Filter for use in a SQL WHERE clause based on the dropdowns and text boxes.

  'e.g. acctcode='123' AND acctdesc Like 'Joe%'

End Function

===================================================================

  <Serializable()> _
  Public Class AcctSearchCriteriaBO
    Inherits MyBusinessBase(Of AcctSearchCriteriaBO)

#Region " Class Variable Declarations "

    Protected mChkAcctCode As Boolean = False
    Protected mChkAcctDesc As Boolean = False
    Protected mChkRouteGrp As Boolean = False
    Protected mChkStatus As Boolean = False

    Protected mCboOperAcctCode As String = "starts with"
    Protected mCboOperAcctDesc As String = "starts with"
    Protected mCboOperRouteGrp As String = "starts with"

    Protected mTxtAcctCode As String = ""
    Protected mTxtAcctDesc As String = ""
    Protected mTxtRouteGrp As String = ""
    Protected mOpgStatus As String = "A"

    Protected mOpgSort As String = "acctcode"
    Protected mSortDirection As ListSortDirection = ListSortDirection.Ascending
    Protected mLstSort As New ArrayList

#End Region

#Region " Constructor "

    Protected Sub New()
      'require use of factory methods 
      Me.Table = "Account Search Criteria"
    End Sub

#End Region

#Region " Business Properties and Methods "

    Public Overridable ReadOnly Property LstSort() As ArrayList
      Get
        If mLstSort.Count = 0 Then
          mLstSort.Add(New DictionaryEntry("acctcode", "Account Code&nbsp;"))
          mLstSort.Add(New DictionaryEntry("acctdesc", "Description&nbsp;"))
          mLstSort.Add(New DictionaryEntry("routegrp", "Route Group&nbsp;"))
          mLstSort.Add(New DictionaryEntry("statustext", "Active&nbsp;"))
        End If
        Return mLstSort
      End Get
    End Property

    Public Overridable Property ChkAcctCode() As Boolean
      Get
        Return mChkAcctCode
      End Get

      Set(ByVal Value As Boolean)
        mChkAcctCode = Value
      End Set
    End Property

    Public Overridable Property ChkAcctDesc() As Boolean
      Get
        Return mChkAcctDesc
      End Get

      Set(ByVal Value As Boolean)
        mChkAcctDesc = Value
      End Set
    End Property

    Public Overridable Property ChkRouteGrp() As Boolean
      Get
        Return mChkRouteGrp
      End Get

      Set(ByVal Value As Boolean)
        mChkRouteGrp = Value
      End Set
    End Property

    Public Overridable Property ChkStatus() As Boolean
      Get
        Return mChkStatus
      End Get

      Set(ByVal Value As Boolean)
        mChkStatus = Value
      End Set
    End Property

    Public Overridable Property CboOperAcctCode() As String
      Get
        Return mCboOperAcctCode
      End Get

      Set(ByVal Value As String)
        mCboOperAcctCode = Value
      End Set
    End Property

    Public Overridable Property CboOperAcctDesc() As String
      Get
        Return mCboOperAcctDesc
      End Get

      Set(ByVal Value As String)
        mCboOperAcctDesc = Value
      End Set
    End Property

    Public Overridable Property CboOperRouteGrp() As String
      Get
        Return mCboOperRouteGrp
      End Get

      Set(ByVal Value As String)
         mCboOperRouteGrp = Value
      End Set
    End Property

    Public Overridable Property TxtAcctCode() As String
      Get
        Return mTxtAcctCode
      End Get

      Set(ByVal Value As String)
        mTxtAcctCode = Value
        PropertyHasChanged("TxtAcctCode")
      End Set
    End Property

    Public Overridable Property TxtAcctDesc() As String
      Get
        Return mTxtAcctDesc
      End Get

      Set(ByVal Value As String)
        mTxtAcctDesc = Value
        PropertyHasChanged("TxtAcctDesc")
      End Set
    End Property

    Public Overridable Property TxtRouteGrp() As String
      Get
        Return mTxtRouteGrp
      End Get

      Set(ByVal Value As String)
         mTxtRouteGrp = Value
        PropertyHasChanged("TxtRouteGrp")
      End Set
    End Property

    Public Overridable Property OpgStatus() As String
      Get
        Return mOpgStatus
      End Get

      Set(ByVal Value As String)
        mOpgStatus = Value
      End Set
    End Property

    Public Overridable Property OpgSort() As String
      Get
        Return mOpgSort
      End Get

      Set(ByVal Value As String)
        mOpgSort = Value
      End Set
    End Property

    Public Overridable Property SortDirection() As ListSortDirection
      Get
        Return mSortDirection
      End Get

      Set(ByVal Value As ListSortDirection)
        mSortDirection = Value
      End Set
    End Property

    Public Overrides ReadOnly Property IsValid() As Boolean
      Get
        'Table level business rule is triggered here. This way the rule only runs once, when you check the validity of the BO.
        ValidationRules.CheckRules("NoneChecked")

        Return MyBase.IsValid
      End Get
    End Property

    Public Overridable ReadOnly Property IsInvalid() As Boolean
      Get
        Return Not IsValid
      End Get
    End Property

#End Region

#Region " Validation Rules "

    Protected Overrides Sub AddBusinessRules()   
      'NoneChecked
      ValidationRules.AddRule(Of AcctSearchCriteriaBO, MyRuleArgs)(AddressOf AtLeastOneIsChecked, New MyRuleArgs("NoneChecked"))
    End Sub

    Private Shared Function AtLeastOneIsChecked(Of T As AcctSearchCriteriaBO, R As MyRuleArgs)(ByVal target As T, ByVal e As R) As Boolean
      If Not (target.mChkAcctCode OrElse target.mChkAcctDesc OrElse target.mChkRouteGrp OrElse target.mChkStatus) Then
        e.Description = "You must check at least one of the search criteria checkboxes."
        Return False
      Else
        Return True
      End If
    End Function

#End Region

#Region " Factory Methods "

    Public Shared Function NewAcctSearchCriteriaBO() As AcctSearchCriteriaBO
      Return New AcctSearchCriteriaBO
    End Function

#End Region

#Region " BusinessBase Overrides "

    Protected Overrides Function GetIdValue() As Object
      Return "AcctSearchCriteriaBO"
    End Function

#End Region

  End Class

 

Hope that helps.

Joe

 

yimiqi replied on Tuesday, August 07, 2007

Thank you Joe for posting your sample code here.

I have already built pretty much the same factory method of the ROC (like AcctList), embedded  Criteria Class (like SearchCriteria), and the ERO (like AcctSearchCriteriaBO) that is used to be bound by search input controls in my project. 

But the issue I'm having is that when the UI passes the AcctSearchCriteriaBO to the SearchCriteria is an empty object or only with its initial values. Therefore when the SearchCriteria is passed to the ROC(AcctList.GetAcctList) DP_Fetch method, it is also empty (doesn't have users' selection).  I think my problem might be in the UI code as the BOs are defined almost the same as yours. I must have missed something somewhere in the UI. 

This is the sample prototype UI code I used to pass the AcctSearchCriteriaBO (I will use the BO name in your example, for communication convenience):

Public Class AccountSearchControl

Private WithEvents mAcctSearchCriteriaBO As AcctSearchCriteriaBO  = AcctSearchCriteriaBO.NewAcctSearchCriteriaBO

Private Sub Search_Click () Handles btnSearch.Click

AccountSearchCriteria.ValidateChildren()

AccountSearchResult.AcctListBindingSource.DataSource = AcctList.GetAcctList(mAcctSearchCriteriaBO)

End Sub

End Class

I do feel somthing is missed from the above code, but...

You said:

"When the user clicks search the screen is unbound into the BO and then the BO is passed to another BO as a parameter to its Fetch method. This way the Fetch method "knows" exactly what the user selected on the search screen."

I think this (the screen is unbound into the BO) is what I missed, therefore the factory method DOESN'T KNOW what the user selected.

What do I need to do to unbound the screen into the BO?

I have a few other questions regarding your sample:

1. The embedded Criteria class (there is more than 1) is given a new name of SearchCriteria and looks like this: >>>

Why do you need more than 1 embedded Criteria class?  I thought the AcctSearchCriteriaBO encapsulated all the search criterias, is that not true?

2.  In the following code

#Region " Factory Methods "

    Public Shared Function NewAcctSearchCriteriaBO() As AcctSearchCriteriaBO
      Return New AcctSearchCriteriaBO
    End Function

#End Region

The code is all fine.  But I'd like to know which way is preferred if I need to initialize some values for the AcctSearchCriteriaBO.  Solution 1 :  Add the initialization in the same function, something like this:

#Region " Factory Methods "

    Public Shared Function NewAcctSearchCriteriaBO() As AcctSearchCriteriaBO 

      Dim obj As New AcctSearchCriteriaBO                                                                                                                                      obj.TxtAcctCode = "9999"
      Return  obj


    End Function

#End Region

Solution 2:  use DP_Create method

#Region " Factory Methods "

    Public Shared Function NewAcctSearchCriteriaBO() As AcctSearchCriteriaBO 

      Return DataPortal.Create(of AcctSearchCriteriaBO)
    End Function

#End Region

Private Overloads Sub DataPortal_Create()

mTxtAcctCode = "9999"

End Sub

Thank you for your time.

 

JoeFallon1 replied on Wednesday, August 08, 2007

Question #1 - simply means that I have other Criteria classes (with different names) that I can use to fetch the same list of Accts. The List BO is not always retrieved as the result of a Search screen.

Key Question:
I think this (the screen is unbound into the BO) is what I missed, therefore the factory method DOESN'T KNOW what the user selected.

You are correct - the web form does a postback and during the PageLoad of the postback you have to unbind the controls on the screen into your Search BO. In your case it would be best to set up a method (UnbindData or something) that is called when IsPostBack = True.  In that method you simply set the porperties of the BO based on the values of the controls on the screen.

(I use 2 way databinding controls from Rick Strahl - so the unbinding happens "automatically" for me. But the method above accomplishes the same thing in a very clear way.)

 

Joe

 

 

 

yimiqi replied on Thursday, August 09, 2007

Joe,

Thanks for your reply and advices.

Question #1 - Okay I see. 

Key Question - Thanks for your suggestion to this key question.  I think I probably didn't explain my issue clear in my last post and even in the original post of this thread.

My issue is: 

The BO properties were updated, but the BO instance I created in the UI was not getting the updated property values (seems this is an even simpler problem). But I need to pass the BO instance with udpated property values ( = user inputs) into the GetList fatory method as parameter, and thereafter it is passed into Criteria class to do DP_Fetch method.  Sorry for the confusion.

Here is what I did:

I called ValidateChildren() to trigger the setting of the BO properties based on the values of the controls on the screen, this is essentially doing the same thing as what the new method you suggested would do. Just instead of doing that in the method, the ValidateChildren() triggers the property setters in the BO, and I can see the properties are updated in the BO, but for some reason the BO instance I created in the UI code isn't getting those property values updated. 

UI code looks something like this:

Public Class AccountSearchControl

Private WithEvents mAcctSearchCriteriaBO As AcctSearchCriteriaBO= _  AcctSearchCriteriaBO.NewAcctSearchCriteriaBO

Private Sub Search_Click () Handles btnSearch.Click

AccountSearchCriteria.ValidateChildren()   AccountSearchResult.AcctListBindingSource.DataSource = AcctList.GetAcctList _(mAcctSearchCriteriaBO)

End Sub

End Class

Note: 

My BO property getter and setter has CanReadProperty(), CanWriteProperty() and PropertyHasChanged(),  may be there is something I don't know about having these in the getter and setter could change its behaviour?

Or am I way off to use the ValidateChildren() to trigger the setting of  the BO properties?

Sorry for not expressing the issue clear enough in the pre posts,  I hope I explained it clear now in this post.

I would appreciate any thoughts you have on this. 

P.S. I also changed the topic of this thread to better describe the problem

JoeFallon1 replied on Thursday, August 09, 2007

1. Is ValidateChildren a method that you wrote? It does the unbinding? How?

2. Here is my Acct search form code: (State is a class that uses Session behind the scenes but allows for strong typing.)

Partial Class AcctSearch
 
Inherits MyBasePage
 
  Protected
mCrit As AcctSearchCriteriaBO

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 
mCrit = State.AcctSearchCriteriaBO

  If mCrit Is Nothing Then
   
mCrit = AcctSearchCriteriaBO.NewAcctSearchCriteriaBO()
    State.AcctSearchCriteriaBO = mCrit
 
End If

  If Not IsPostBack Then
    
Me.DataBind()
  End If

End Sub

Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSearch.Click

  Me.UnbindData()  'this sets all the properties of the mCrit BO based on the values in the screen.
  State.AcctSearchCriteriaBO = mCrit   'store the BO in Session and pass it to the Result page.
  Response.Redirect("~/AcctResults.aspx")
End Sub

End Class

 

===============================================================================

This is the essential code on the Result page:

Partial Class AcctResults
 
Inherits MyBasePage

Protected mCrit As AcctSearchCriteriaBO
Private mAcctList As AcctList

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 
mCrit = State.AcctSearchCriteriaBO
  mAcctList = State.AcctList
 
 mAcctList = AcctList.GetAcctList(mCrit)
  doDataBind()
End Sub

End Class

===============================================================================

My code looks a lot like yours. The basic difference is that when my form unbinds on postback my BO keeps its values. You need to debug your form and see why the BO gets the values set but  then they disappear.

Joe

 

yimiqi replied on Thursday, August 09, 2007

Joe,

1.  ValidateChildren is not a method I wrote.  It is:

Public Overrides Function ValidateChildren() As Boolean

Member of: System.Windows.Forms.UserControl

2.  Yeah, my code does look a lot like yours, mine is a windows application though.

The basic difference is that when my form unbinds on postback my BO keeps its values. You need to debug your form and see why the BO gets the values set but  then they disappear.  >>> You are absolutely right.

Note:  I got the idea using ValidateChildren() to trigger the BO properties' setter by Rocky's post in following link

http://www.lhotka.net/Article.aspx?area=4&id=54b7097e-2eb5-476d-842b-98fde95c2006

I will post if I find anything in debugging.

 

RockfordLhotka replied on Thursday, August 09, 2007

The point of that article is to allow a dual-level validation scheme. One level is purely in the UI, the other is purely in the business object.

ValidateChildren() is there to validate the child controls in the UI. It has nothing really to do with the business object in any direct sense.

The assumption in the article you reference is that the UI allows entry of values that the object would never accept. In that case, the invalid value is in the UI, but not the object. The UI knows the value is bad, but leaves it on the screen for the user to see (probably along with an errorprovider indicator).

The code in the save button's click event first checks to see if ValidateChildren() returns true - which would indicate that there are no UI validation errors. If that check passes, we know that the values in the UI are in the object (since the UI liked the value, data binding put it in the business object automatically), and so the object's IsSavable property is checked.

yimiqi replied on Thursday, August 09, 2007

Thanks Rocky for clarifying the usage of ValidationChildren() in your article, I have a better understanding of the purpose of that article now.

I tried, but I'm still not able to track down what the cause is that is making my BO properties disappear:

Recap of the scenario I'm trying to implement:

1.  UI search control (with many user input controls on it)  is bound to an Editable Businees Object Root

2.  The BO has properties that are bound to each user input controls

3.  Set BO properties with user inputs

4.  Send the BO with user input values to the Criteria class

...

My problem resides in step 3, so let me step through what I did in step 3.

a. I called UIControl.ValidateChildren() from UI class to trigger the BO property setters. 

   The call stacks are as following:

Csla.dll!Csla.Core.BusinessBase.IEditableObject_BeginEdit() Line 650 Basic

> Csla.dll!Csla.Core.BusinessBase.CanWriteProperty(String propertyName = "ID", Boolean throwOnFalse = True)

> Csla.dll!Csla.Core.BusinessBase.CanWriteProperty(String propertyName = "ID")

> Csla.dll!Csla.Core.BusinessBase.VerifyAuthorizationCache()

> Csla.dll!Csla.Core.BusinessBase.get_AuthorizationRules()

> Csla.dll!Csla.Security.AuthorizationRules.HasWriteAllowedRoles(String propertyName = "ID")

> Csla.dll!Csla.Security.AuthorizationRules.get_InstanceRules()

> Csla.dll!Csla.Security.AuthorizationRulesManager.GetRolesForProperty(String propertyName = "ID")

> Csla.dll!Csla.Security.AuthorizationRules.HasWriteAllowedRoles(String propertyName = "ID")

> Csla.dll!Csla.Core.BusinessBase.PropertyHasChanged(String propertyName = "ID")

> Csla.dll!Csla.Core.BusinessBase.get_ValidationRules()

> Csla.dll!Csla.Core.BusinessBase.MarkDirty(Boolean suppressEvent = True)

> Csla.dll!Csla.Core.BindableBase.OnPropertyChanged(String propertyName = "ID")

> Csla.dll!Csla.Core.BindableBase.raise_PropertyChanged(Object sender = {Application.Business.MyBO}, System.ComponentModel.PropertyChangedEventArgs e = {System.ComponentModel.PropertyChangedEventArgs})

After these calls, in  My BO class, the BO properties were updated

But right after the call of ValidationChildren(), if I do call the getter of the BO properties that were just updated, they already lost their updated values.

b.  So If I do a test right after the UIControl.ValidateChildren() statement with something like

dim mSearchBO As SearchBO = SearchBO.NewInput

dim a As Int32

a = mSearchBO.ID

then a returns 0, which is its initial value

What did that happen?  All the BO properties were not retained?  What am I missing?

My BO property is set up like this:

Public Property ID As Int32

Get

       CanReadProperty("ID", True)

Return m_ID

End Get

Set (ByVal value As Int32)

       CanWriteProperty("ID", True)

If m_ID <> value Then

         m_ID = value

         PropertyHasChanged("ID")

End If

End Set

End Property

Questions:

Am I completely off approaching this direction to implement my scenario? especially the part using ValidateChildren() to trigger BO property update

Is my BO property set up incorrectly? The calls to CanReadProperty, CanWriteProperty, and PropertyHasChanged, are they needed? (I tried to comment those line out but it didn't make difference)

Otherwise, why is this not working?

I appreciate any inputs/insights on this issue.

 

 

 

RockfordLhotka replied on Thursday, August 09, 2007

Why is there a step 3?

 

The whole point of data binding is so you don’t have to set object properties – that’s done by data binding so you don’t have to.

 

Rocky

yimiqi replied on Thursday, August 09, 2007

RockfordLhotka:

Why is there a step 3?

 

The whole point of data binding is so you don’t have to set object properties – that’s done by data binding so you don’t have to.

 

Rocky

I did a quick test after Rocky's above response as following:

Comment out the call to ValidateChildren() in Search Screen. 

Start the app, enter some inputs on the search screen, create instance of the BO, send the BO to GetList fatory method as a parameter, the BO is empty. 

So the test failed.

I guess the reason I chose to use ValidateChildren() to trigger the BO property set is something called data binding kept in the back of my brain.  The ValidateChildren() did the property set for me behind scene (of course not perfectly in my case) magically, i didn't set up a method just to set the object property (that is something I kinda knew I shouldn't do). 

But the question is, where does the data binding come into play in my scenario?  How does the BO know users' input (see, I still don't understand how data binding works even if I thought I kinda know).  Is everything set up at design time?  I checked the data binding property, it all seems right there.  What is the real trigger?  When will the BO that is bound by the search control know its property has changed?  As soon as the user clicks search? 

Rocky, could you point me to the direction that I can learn to re-understand Data Binding in your project traker application?

Sorry for so many questions

Thanks for any info

RockfordLhotka replied on Thursday, August 09, 2007

The best place to start is to read Chapter 9 where I describe how to create the PTWin project, including setting up data binding. Note, however, that there’s some errata for that chapter, so make sure to check that out as well (from www.lhotka.net under the CSLA .NET menu).

 

Or read Chris Sells’ book on Windows Forms, because I think he talks about data binding in more general terms.

 

You are right though, data binding is all set up at design time – drag and drop the properties from the Data Sources window onto your form and it all gets set up automatically. All you need to do in code is set the bindingSource.DataSource property.

 

Rocky

yimiqi replied on Thursday, August 09, 2007

Rocky,

Thanks for your guidance, I will read from Chapter 9 again.  I don't have Chris Sell's book in hand,  will consider to buy one though.

A couple of more questions just came up:

1.  So you don't think I need to call ValidateChildren() to do what I intend to do in my case?

2.  If you already already have a BO and a control/form using that BO as the data source.

In the case of changing your control/form to bind to a different BO but with the same properties as the original BO, do you have to create the different BO first and drag and drop the properties from the new Data Source, basically meaning recreate your control/form even if it has the exact same controls on it but is just bound to a different BO (data source)?  Or can you just adjust the BindingSource.DataSource on the existing control/form? Will the second approach cause confusion when comes to Data Binding?

3. What about creating inherited controls impacting data binding?

The controls in your project tracker example pretty much created straightly from Windows.Forms.UserControl.  In my application,  I use lots of inherited controls.  and aloso have drag controls on another control etc.  I wonder if that caused some confusion in the Data Binding as well.

4.  I do use bindingSource.DataSource in my code, good to know that is the only code needed regarding data binding (rest is at design time).

Just want to throw the questions out there.  Sorry it becomes another lengthy post

Thanks for your time

RockfordLhotka replied on Thursday, August 09, 2007

You bring up some interesting questions, and I don’t know the answers to all of them.

 

1.       I’m not sure why you are calling ValidateChildren(), but its purpose is to do control-level validation (in the UI, having nothing to do with the business object). I find it primarily useful when dealing with object properties of type other than string, where the UI control can be invalid, but the business object property might not be (because it doesn’t even have the real value)

2.       The bindingSource architecture is designed to work on object shape not on specific types. So you can set bindingSource.DataSource to any object that has the same shape as the one used at design time. What this means, is that any object with exactly the same properties as are data bound can be used (the object can even have extra properties – they are just ignored). Pretty cool.

3.       I don’t think this matters, but it depends on what you do in your subclass. Simple (property-level) data binding is independent of control implementations and works through reflection at the property level. I think there are some attributes you might use on properties that could interfere, but normally it just works. Complex (entire object) data binding is much more complex, because the control actually interacts with the object directly – this is like a grid or similar control. Very few people write complex data binding controls, because it is … well … complex.

4.       The only thing to remember with setting the DataSource, is that sometimes you need to “clear” it before changing the source – for a root bindingSource that means setting it to null/Nothing, but for child bindingSource controls that means setting the DataSource back to the parent bindingSource – see Chapter 9 for info.

 

Rocky

yimiqi replied on Saturday, August 11, 2007

Rocky,

Thanks for your answers to my questions, they are very helpful.

1.  The idea to call ValidateChildren () is intrigued by your article without fully truly understanding its purpose as you explained to me in this post.  When I used ValidationChildren() and step through the code, it did what I wanted to do, that is, to set the object properties.

But, you are right, I don't have to tell set the object properties, data binding does it all. 

However, removing ValidateChildren() didn't solve my problem.  After hours of debugging, it turned out that the problem had something to do my using a complex DB key as a unique identifier for the control.  Once I changed to use Guid as the unique identifier, my problem was solved.  Data binding is doing its job.  I don't really need to call ValidationChildren() to set the object properties.  However, it will give you the same result if you still leave that call in the code, plus, it does the control-validation in the UI for you.  So I will still use ValidationChildren() in my code, with knowing better why I'm using it though :-)  Thanks for your guidance!

2.  I'll have to say the BindingSource is so powerful and so cool!  Thanks for making me truely realize that.

3.  Again, thanks for educating me more on the data binding.  I really like your very clear way of explaining a confusing thing to a newbie like me.  I checked all my base controls, inherited controls, good they are all using simple binding except for the grids (is using complex binding).

4. Thanks for the tip.  I did read this in your book or see it on your DNR show.  Great tip!

Thanks so much Rocky for your advices and your dedication to this community, ... and your great framework! 

Thanks to Joe too, for reviewing my code, giving me your suggestions, and posting your own code for my reference. 

I learned a ton from all of you, and this forum!

Rocky, have a wonderful vacation next week, you deserve it!

Copyright (c) Marimer LLC