Stumbling Through

Join me as I stumble, bumble and fumble my way through some new developer technologies. We'll laugh, we'll cry, there may be a mouse tossed through a monitor, but in the end we will all hopefully learn something.
in

Stumbling Through: WPF (Databinding Part I)

I have a love-hate relationship with databinding. I believe it was first introduced to me very early in my career, either in some incarnation of Visual Basic (4, perhaps?) or in the language of choice for my first job out of college: Centura Team Builder (kudos to anyone who has ever heard of that language). Wherever I heard about it, I remember falling on it like a starving man on a roast beef sandwich. I thought it was the coolest thing ever, and I told everyone how it is going to make all of our data-driven interface logic completely obsolete. Well, to make a long story short, I never could get data binding to do everything I wanted as easily as I wanted it, and it fell out of favor. With every new version of Visual Basic and then Visual Studio .NET, I always leapt back into their 'new and improved' databinding until I ultimately left disappointed yet again. I finally jumped back on board with databinding for good in Visual Studio 2005, where I think they finally got it right (or at least close enough for me). Seeing as though WPF is built on or around the same framework, its databinding capabilities should be at least as good as Win Forms in 2005, right? Well, that is what I am going to figure out by stumbling through databinding in WPF.

 

The first order of business is setting up something to databind TO. I'm going to use the same project from my previous posts, which now consists of a stylized, transparent listbox on a window with a nice stone background hijacked from some generic windows desktop bitmap. Since I am a strong proponent of the whole binding-to-collections way of thinking, I'm going to create two classes: PersonCollection and Person. Person will be made up of first and last name properties, while PersonCollection will have a 'LoadAll' method to add three person instances to its underlying collection. Now something that I haven't mentioned yet is which 'collection base' should be used as the base class for our PersonCollection class. Instead of one of the traditional base collection classes, we will be using the 'ObservableCollection' class, which is supposed to include support for property changed and validation events. We'll investigate what this does for us when we start consuming this object. This class is a part of the System.Collections.ObjectModel namespace, and is generic so we'll have to specify the type of object it will contain (Person).

 

Here is the source for the Person class:

 

namespace StumblingThroughWPFPartI
{
    public class Person
    {
        String _firstName;
        String _lastName;

        public Person(String firstName, String lastName)
        {
            _firstName = firstName;
            _lastName = lastName;
        }

        public String FirstName
        {
            get
            {
                return _firstName;
            }
            set
            {
                _firstName = value;
            }
        }

        public String LastName
        {
            get
            {
                return _lastName;
            }
            set
            {
                _lastName = value;
            }
        }

    }
}

 

Here is the source for the PersonCollection class:

 

namespace StumblingThroughWPFPartI
{
    public class PersonCollection : ObservableCollection<Person>
    {

        public void LoadAll()
        {
            this.Add(new Person("Test", "Guy"));
            this.Add(new Person("Another", "One"));
            this.Add(new Person("Someone", "Else"));
        }
    }
}

 

As you can see by the class definitions, they are a part of the 'StumblingThroughWPFPartI' namespace. Our test window, where we will be using these classes, has no idea about that namespace so we need to register it at the top of the page like this:

 

xmlns:StumblingThroughWPFPartI="clr-namespace:StumblingThroughWPFPartI"

 

Now we can instantiate our PersonCollection object by adding it to the resource dictionary like this:

 

<StumblingThroughWPFPartI:PersonCollection x:Key="_personCollection"/>

 

Defining our instance this way automatically instantiates the class as an empty Person Collection and puts it into the resource dictionary with a key of '_personCollection'. To load up our collection, we need to access it in the code behind to invoke its 'LoadAll' method. Following my WinForms inutition, I attempt to double click the form to bring up its 'Load' event handler, thinking I'd just populate the collection in the load event. Cool, not only did it bring me to the 'Window_Loaded' event handler, it also threw something in my XAML that tells it where do go for the 'Loaded' event. This attribute is a part of the Window tag:

 

Loaded="Window_Loaded"

 

Now we can code up our Window_Loaded event handler. The first order of business is to retrieve our Person Collection from the resource dictionary. This can be achieved in the following line:

(PersonCollection)this.Resources["_personCollection"];

 

We can further enhance this line, since we aren't worrying about error handling at this time, to load our object as well:

 

((PersonCollection)this.Resources["_personCollection"]).LoadAll();

 

So now we have our fully loaded Person Collection in the resource dictionary, how do we bind our list box to display the first name of every person? Back in our XAML, lets remove any ListBoxItem tags that may still be there from the previous posts. In our empty list box, I'm looking for two properties: Where is the data source, and where is the Display Member? Display Member is there as DisplayMemberPath, calling it a 'path' makes me think you can bind into nested hierarchies but I'm not going to think about that yet. I'm just setting that property to 'FirstName'. The only thing I can find that is roughly equivilent to Data Source is 'ItemSource'. What I've seen of the syntax for this property seems pretty funky... I know that in order for it to do what we want, it needs to look like this:

 

ItemsSource="{Binding Source={StaticResource _personCollection}}"

 

My interpretation of this is that we are sending ItemSource equal to a new binding, whose source is the current dictionary instance of the item with the '_personCollection' key. Running the project has the expected results:

 

image

 

Next, I'm going to try and bind the selected first name to a text box, allow editing and maybe even force validation.

Leave a Comment

(required) 

(required) 

(optional)

(required)