Click here to Skip to main content
Click here to Skip to main content

Setting two bindings on a single WPF control

, 25 May 2008
Rate this:
Please Sign up or sign in to vote.
This article demonstrates how to set two bindings on a WPF control, yielding significant amount of code reduction for developers & boosting their productivity.

Introduction

One of the major motivations to move to WPF is to leverage on its Binding framework. This article assumes that you are already comfortable with this wonderful piece of technology. In here, I will try addressing a common issue which might look unusual at first. I will start with a scenario on which we will be building during the course of the article. I have kept things simple, so that the underlying message is clear, but the same solution can be applied to more complex scenarios yielding significant code reduction & easy maintenance.

Background

Assume you have a patient screen which displays details about a given patient. On this Screen you have a ComboBox which displays various blood groups. Default selected blood group in the ComboBox should come from the current patient that is being displayed on the screen. Also whenever selection changes in combo box it should change the displayed patient’s blood group as well.

A Look at the expected output

Building the Code

To start with we want to display a bunch of items inside a WPF control in this case a ComboBox. These items would typically reside in a master table inside a Database. To get this up & running you have to set the local data context for the ComboBox along with its ItemsSource property. Let’s see some code to put things in perspective. Below is our class BloodGroup (you can assume a similar corresponding table inside the Database).

public class BloodGroup : INotifyPropertyChanged
{
private int _code;
private string _name;

public int Code
{
get { return _code; }
set
{
_code = value;
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Code"));
}
}
public string Name
{
get { return _name; }
set
{
_name = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

Consider the XAML and code below to display a list of blood groups inside a ComboBox. Ideally you would fetch this data from a Database but for simplicity I am going to build an in memory collection.

<StackPanel>
        <ComboBox x:Name="cbBloodGroups" ItemsSource="{Binding}" DisplayMemberPath="Name" SelectedValuePath="Code" />
</StackPanel>

public Window1() 
{ 
   InitializeComponent(); 
   ObservableCollection<BloodGroup> bloodGroups = 
          new ObservableCollection<BloodGroup>() { 
          //Fill the collection; this could have been done via 
          //objects retrived from a WCF Service 
               new BloodGroup() {Code = 1, Name = "O+ve"}, 
               new BloodGroup() {Code = 2, Name = "O-ve"}, 
          }; 
   cbBloodGroups.DataContext = bloodGroups; 
} 
Fine, so this is simple stuff. Now starts the real problem. Let’s say that we have a Patient class with a single property called BloodGroupCode as follows:
public class Patient: INotifyPropertyChanged 
{ 
    private int _bloodGroupCode; 
    public int BloodGroupCode 
    { 
        get { return _bloodGroupCode; } 
        set 
        { 
           _bloodGroupCode = value; 
           if(PropertyChanged != null) 
              PropertyChanged(this, new PropertyChangedEventArgs("BloodGroupCode")); 
        } 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
} 
ComboBox’s current item of display should be decided by the BloodGroupCode property of Patient’s class. How can we set that? We can’t remove ItemsSource Binding on the combo box or replace it as that is providing items. So we need to add one more binding to the combo box. Let’s see how.

Solution

Patient object ideally would be a row in some Database table, to which we would get access only at run time. Hence we can create an ObjectProvider in the resource collection of the window & initialize its ObjectInstance property to null. At run time when we retrieve the actual object from Database we can do the assignment. Once done with adding ObjectProvider, we can access the patient object via StaticResource markup extension in the ComboBox and set the ComboBox’s SelectedValue property. This works like a charm for the issue we are trying to address. Steps are as below:

First Step

Define an Object Provider in Resource collection of your Window / Page / UserControl & set SelectedValue Property for the combo box by using StaticResource extension with corresponding Path value.
<Window.Resources> 
  <ObjectDataProvider x:Key="dataProvider" ObjectInstance="{x:Null}" /> 
  </Window.Resources> 


<StackPanel> 
  <ComboBox … 
       SelectedValue="{Binding Source={StaticResource dataProvider}, 
       Path=BloodGroupCode}" /> 
</StackPanel>

Second Step:

Next step is to set ObjectInstance which was originally initialized to Null.

public Window1() 
{ 
    InitializeComponent(); 
    … // Binding the Combo Box with items as before 
    var dataProvider = this.Resources["dataProvider"] as ObjectDataProvider; 
     if (dataProvider != null) 
    dataProvider.ObjectInstance = new Patient() {BloodGroupCode = 2}; 
    //The above assignment could be object retrived via WCF Service 
} 
That’s it. With Patient Object implementing INotifyPropertyChanged interface the binding is bidirectional. When you modify the Patient Object the ComboBox selection changes, & when you change the selection in ComboBox the underlying Patient object’s BloodGroupCode property changes. Hence you have two bindings set on a combo box & both work as expected.

Conclusion

While building a UI, many times we need to bind a control to multiple sources. For instance, one source which provides the items to the control & other source which selects the current item to be displayed. This article demonstrates how to do the same in WPF, yielding significant amount of code reduction for developers & boosting their productivity.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author


Comments and Discussions

 
Generalnot able to downlaod the code for the same PinmemberAmithaRaghu16-Feb-11 0:34 
GeneralLink... PinmemberKenan E.K.6-Aug-09 0:00 
GeneralNice one. Gets my 5 PinmvpPete O'Hanlon25-May-08 22:10 
GeneralRe: Nice one. Gets my 5 PinmemberNirajRules25-May-08 23:28 
General[Message Removed] PinmemberMojtaba Vali25-May-08 17:59 
GeneralRe: nice light on a dark subject PinmemberNirajRules25-May-08 22:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140814.1 | Last Updated 25 May 2008
Article Copyright 2008 by Niraj Bhatt
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid