Erik Porter's Blog

Life and Development at Microsoft and Other Technology Discussions

News

    WindowsForms DataBinding

    I'm in the middle of working on my presentation (yes, that's right, I'm not done yet...I'm a procrastinator and love working under pressure) and happened to have just blogged about Strongly Typed Collections and thought of something I had done in a project a while back related to DataBinding in WindowsForms.  Even though it's extremely simple, this will hopefully show you that DataBinding in WindowsForms is extremely powerful.

    First off, create a new Form, slap a ComboBox in the middle and name it "cmbPeople".  Then take the Collection I created in my last post called "PeopleList" and plop it into your Form (the declaration and filling of it anyway).  Now when the Form loads, simply put this line of code:

    cmbPeople.DataSource = PeopleList

    Now, what this actually does is bind the objects themselves to the Items Collection of the ComboBox.  If you're used to ASP.NET, this is quite a bit different.  In WebForms, when you DataBind, ASP.NET actually takes your Collection, DataTable, DataReader, etc and builds the appropriate child controls and adds them into the Items Collection for whatever Control you're binding to and then actually has no reference to the original bound object.

    This idea should trigger a few things in your mind.  What about the DataReader?  It is connected only, read only & forward only data.  Well, if you were wondering if it could be bound to in WindowsForms, you thought right.  It definitely CAN NOT be bound to, because again, in WindowsForms, you're binding to the actual objects and if you close a DataReader, then all the data is no longer there.  The other big reason you wouldn't be able to bind to a DataReader is that only instances that Implement IList can be bound to in WindowsForms.

    Ok, so now that we've gotten that out of the way, how do we tell our ComboBox what data to display from our DataSource that we set earlier?  There are a couple different ways.  First, let's talk about the easier yet more disjointed way to do it.

    Being that the "Person" class has a FirstName and LastName Property, more than likely we'd want to display first name, then a space, then the last name.  This can be done really easily by overriding the ToString Function like so:

    Public Overrides Function ToString() As String
        
    Return Me.FirstName & " " & Me
    .LastName
    End Function

    So now if we run our little Form, you should see in the ComboBox all the Items that were adding in the PeopleList Collection by their First and Last Name.

    Now for kicks (and to demonstrate why binding to the actual objects is so powerful) let's display a message box showing the ID of the currently selected Person in the ComboBox:

    Private Sub cmbPeople_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmbPeople.SelectedIndexChanged
         MessageBox.Show(DirectCast
    (cmbPeople.SelectedItem, Person).ID.ToString)
    End Sub

    So as you can see, the SelectedItem itself IS the actual Person object in our People Collection that we're bound to, so you we can just cast it and grab whatever Property we want (or anything else for that matter [call a method, grab a Public Member Variable, etc]).  How cool is that?  Try binding to a DataTable.  You'll find that the SelectedItem holds the current DataRowView.

    In ASP.NET, to access the data again, you'd have to actually resetup the data (depending on what you're using, such as a DataTable, you'd have to requery your DB) and use the SelectedIndex to go find the correct Item to get at whatever data you needed.  I'm not biased or anything, I swear.  I really do love ASP.NET, just pointing out some key advantages here.

    Great, that was easy, now how about a little "tighter" way of binding to our data.  There are two other Properties we can take advantage of to bind a little tighter to our data.  DisplayMember and ValueMember.  If you're used to ASP.NET, these Properties are similar to DataTextField and DataValueField and like those two, are both also Strings that are the "fields" (or Public Properties) you want to represent the underlying "value" and the field to be "displayed".

    So let's set that up instead.  Granted, this particular example (the People Collection) isn't a very good one, as we will have to pick between showing the first name or the last name instead of both, but for this example, it will be better to keep it simple instead.  Leave in the line of code that set the DataSource, but go back into the Person Class and remove the ToString Function.

    Now, before setting the DataSource, put these two lines of code:

    cmbPeople.DisplayMember = "FirstName"
    cmbPeople.ValueMember = "ID"

    Now, to do what we did last time and display the ID Property of the currently selected item in a message box, we're going to use the SelectedValue Property:

    Private Sub cmbPeople_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cmbPeople.SelectedIndexChanged
         MessageBox.Show(cmbPeople.SelectedValue.ToString)
    End Sub

    Run the Form and you should now see the FirstName in the ComboBox for each item and when you change to a different item, you'll see the ID just as before.  Again, this works great with DataTables as well, but instead of a Property name, you could set DisplayMember and ValueMember to Column Names.  And also, just as it was in the first binding example, SelectedItem will still return back a reference to the actual object that is currently selected.

    Hopefully, if you had any questions about simple binding before, this has helped you a bit.  Maybe even if you're an avid ASP.NET user, but have peaked around at WindowsForms, this should explain some of the differences in DataBinding between the two.

    Have more DataBinding questions in WindowsForms?  Check out the forums.

    Comments

    friend said:

    In the Person Class you could also add a property like the one below:

    Public ReadOnly Property FullName() As String
    Get
    Return Me.FirstName & " " & Me.LastName
    End Get
    End Property

    ' And be able to use the property in a databound ComboBox as you suggested,
    ' but pull the displymember from the new property
    cmbPeople.DisplayMember = "FullName"
    # December 5, 2003 6:43 PM