Windows Presentation Forms (WPF) brought a lot of cool features to C#. Hardware accelerated rendering, XAML backed control layout, and more versatile ways to bind your data to your controls. In WinForms there were ways to bind data base schemes to controls, but all in all it was a pain and rather limited. WPF opens up binding to almost any type. If you don't know what binding is, binding is when a particular property is "bound" to a control such that when the value changes, the control is updated, and in some cases, if the control is changed, the property is updated. I've thrown together a very basic application to help demonstrate some of the basics of binding, let me walk you through it.
The example I learned binding on was a simple Address Book application, storing names, numbers and other information about your friends and family. Let's cut the chit chat and jump into it. For a simple address book, we need a class to hold all the information for a single person. Here's the class I used:
public class Entry {
public String LastName { get; set; }
public String FirstName { get; set; }
public String Email { get; set; }
}
Before you ask, yes, they have to be properties, public fields are not good enough. Why? Why not. I'm sure it has to do with Reflection, when I find out the details, y'all will be the first to know. Moving on! Normally I would set each properties set to be private, but I'm going to show you how to do Two-Way binding, and for that to work, it'll have to be able to read and write to the properties. Now that we have the structure for an entry in the address book, let's create the collection to hold multiple entries. In the main form, I added an ObservableCollection<Entry> object as follows:
public ObservableCollection<Entry> AddressBook { get; private set; }
We're going to be binding to this as well so it will also have to be a property. Now that we have an individual entry defined, and a place where we can hold multiple entries, we need a place to display them. Back in the main window, I added a ListView with a few Column Definitions:
<ListView x:Name="ContactsList" ItemsSource="{Binding Path=AddressBook}" Width="300">
<ListView.View>
<GridView>
<GridViewColumn Header="Last Name" Width="95" DisplayMemberBinding="{Binding Path=LastName}" />
<GridViewColumn Header="First Name" Width="95" DisplayMemberBinding="{Binding Path=FirstName}" />
<GridViewColumn Header="Email" Width="95" DisplayMemberBinding="{Binding Path=Email}" />
</GridView>
</ListView.View>
</ListView>
Let's break down the ItemsSource property and see what's going on. Like any other attribute, it's just another name/value pair, so far pretty normal. To denote that we're not simply adding text to this attribute, the entirety of the attribute's value is wrapped in curly braces. The first word inside the brackets is the word Binding, indicating that's what we're doing. Next is the area where parameters are passed to the binding. For the ItemsSource of the ListView, we simply set it to the ObservableCollection<Entry> we made in the code behind. This means that for each item in the ObservableCollection<Entry> there will be an item in this ListView. As we dive deeper into explaining the layout of each item in the ListView, since we previously bound the ObservableCollection<Entry> to the whole control, then for each item we can bind to the properties of an Entry. That's what DisplayMemberBinding does, it relates a property on the Entry object to use to display within that column.
If you run the app now, you'll notice that it doesn't display anything in the ListView. We don't need to just relate the Binding to the property in the XAML, but we also need to relate an object to the controls. In order to do this, we set the DataContext of the window to the window itself. It sounds redundant, but we can set this DataContext to any object. Let's also add a starting entry to our ObservableCollection<Entry> so we can see when it works.
AddressBook = new ObservableCollection<Entry>();
Entry test = new Entry() { LastName = "Ogburn", FirstName = "Corey", Email = "coreyog@gmail.com" };
AddressBook.Add(test);
this.DataContext = this;
Now if you run the application, you should see my entry in the ListView. That's fine and all except that we can't add or remove or even edit these entries. It's simply a viewer and that does us no good. Let's add a few textboxes so when you click an entry, you can edit it's information. Previously if we wanted to do this, we'd attach to the SelectedIndexChanged event and use the SelectedIndex to retrieve the information and fill the textboxes. Binding will save us a step here too. We don't have to write a single line of C# in order to copy information from the ListView into the textboxes. Here's the XAML of these textboxes, positioning attributes have been removed for conciseness:
<TextBox Name="FNameBox" Text="{Binding ElementName=ContactsList, Path=SelectedValue.FirstName}" />
<TextBox Name="LNameBox" Text="{Binding ElementName=ContactsList, Path=SelectedValue.LastName}" />
<TextBox Name="EmailBox" Text="{Binding ElementName=ContactsList, Path=SelectedValue.Email}" />
We are not limited to binding to properties in the code behind, we have access to other controls in the window. By specifying an ElementName in the binding string, we can Bind directly to another control's properties. Here, we bind to the ContactsList ListView control, and we set the path to it's SelectedValue, which is an Entry, and then to the Entry's properties. Now when the selected value of the ListView changes, these controls are updated to display the newly selected value's properties. Again, without a single line of C#. The binding flows both ways here, so if you change an entry in the textboxes, you change the entry in the ListView, and even all the way back in the original ObservableCollection<Entry>! In the project I threw together for this, I added a new and delete button. Neither of these buttons directly impact the ContactsList ListView, they both impact the AddressBook and thanks to the binding, the control is updated.
This is a very basic example and will get you headed in the right direction. As we've seen, binding simplifies a lot of complexities for handling lists and binding across events. XAML and binding join together to help handle the controls separately from the code behind. No longer are you required to write C# code to handle some of the more menial visual aspects. Features like this is what makes the Model-View-ViewModel design pattern possible.
As promised, here's the project files. Play with them, experiment, keep track of your friends' and family's contact information, do whatever.