Binding a WPF ComboBox to a display source and a binding source


Home | Blog | CSLA .NET | CSLA Store

24 April 2007

I am building a WPF UI for my ProjectTracker CSLA .NET sample app. On the whole this is going pretty well, and I anticipate being done within the next couple days. I’ve found and fixed a couple bugs in CSLA – one in BusinessListBase that’s been there forever, and one in ValidationPanel that caused a null reference exception. While I fixed that last one, I optimized the code a bit, which does seem to make the control a bit faster. But one thing I spent a ridiculous amount of time on was the simple process of getting a ComboBox control to bind to one data source to get its list of items, and to the business object property for the key value. Google turned up a number of search results, none of which really addressed this particular scenario – which seems odd to me given how common a scenario it is… In ProjectTracker, a person (resource) can be assigned to a project. If they are, they are given a role on that project. The Role property is numeric – a key into a name/value list, and a foreign key into the Roles table in the database. In Windows Forms and Web Forms the UI handles translating this numeric value to a human-readable value through ComboBox controls, and obviously WPF can do the same thing. The trick is in figuring out the XAML to make it happen. Here’s the ComboBox XAML:             <ComboBox               ItemsSource="{Binding Source={StaticResource RoleList}}"               DisplayMemberPath="Value"               SelectedValuePath="Key"               SelectedValue="{Binding Path=Role}"               Width="150" />

<?xml:namespace prefix = o ns = “urn:schemas-microsoft-com:office:office” /> 

Let’s break this down. The ItemsSource property specifies the data source for the data that will populate the display of the control. In my case it is referencing a data provider control defined like this:   <Page.Resources>     <csla:CslaDataProvider x:Key="RoleList"                            ObjectType="{x:Type PTracker:RoleList}"                            FactoryMethod="GetList"                            IsAsynchronous="False" />   </Page.Resources>   This data provider control loads a name/value list object called RoleList (that inherits from Csla.NameValueListBase). The child objects in this collection expose properties Key and Value. You can see how the ComboBox uses the DisplayMemberPath to specify that the Value property from the name/value list should be displayed to the user, and the SelectedValuePath specifies that the Key value from the list should be used to select the current item (the Key value is not displayed to the user). Then notice that the SelectedValue property is used to bind to the main business object. This binding statement sets a path to a property on the overall DataContext for the ComboBox, which in my case is actually set through code at the Page object level:       this.DataContext = project; So all controls on the entire page, by default, bind to a Project object, and this includes the ComboBox. Remember though, that the Role property on the Project is a numeric index value. And so is the Key value from the name/value list. The ComboBox control connects these two automatically. So when the business object’s Role property changes, the ComboBox automatically changes the displayed/selected item. Conversely, when the user changes the ComboBox selected item, that automatically causes the business object’s Role property to change.