Search code examples
c#wpfcomboboxobservablecollection

Binding a ComboBox to an ObservableCollection


I have a WPF C# application.

I am using a ComboBox and I have set its ItemSource property to an ObservableCollection.

The problem I have is that when I modify this collection the changes are not reflected in my drop down.

so I am wondering what I have done wrong?

This is my class object:

public class JobTicker
{
    public string CustomerRef { get; set; }
    public string JobRef { get; set; }
    public int JobId { get; set; }
    public string CustomerJobDetails { get; set; }
    public string CustomerName { get; set; }
}

I bind to my collection:

ActiveState.JobsActive = new ObservableCollection<JobTicker>('data from a list');

my declaration of the collection variable:

public static ObservableCollection<JobTicker> JobsActive = new ObservableCollection<JobTicker>();

My ComboBox (which is on a UserControl of mine that is loaded when my app starts)

<xctk:WatermarkComboBox  x:Name="cboActiveJobs" Grid.Row="1" Grid.Column="2" 
    Width="250" Watermark="Select Customer"          
    DisplayMemberPath="CustomerJobDetails" 
    HorizontalContentAlignment="Center"                     
    SelectionChanged="cbo_SelectionChanged" 
    DropDownOpened="cbo_DropDownOpened" 
    DropDownClosed="cbo_DropDownClosed"
    Style="{StaticResource ComboBoxFlatStyle}"
    />

and my code behind:

cboActiveJobs.ItemsSource = ActiveState.JobsActive;

Now if I modify 'ActiveState.JobsActive' I would expect changes to be reflected in my ComboBox but they are not.


Solution

  • The code you have isn't actually binding it. It's just assigning a collection to a property.

    The combo box's ItemsSource property can't listen for notifications from the ObservableCollection. Instead, you need an instance of the Binding class to listen for those notifications and make the UI updates happen. Binding is where all the magic is. You could create one programmatically in code behind and attach it (see links below), but the easiest and by far most common way is to bind in XAML:

    <xctk:WatermarkComboBox  
    
        ItemsSource="{Binding JobsActive}"
    
        SelectedItem="{Binding SelectedCustomer}"
    
        x:Name="cboActiveJobs" 
        Grid.Row="1" 
        Grid.Column="2" 
        Width="250" 
        Watermark="Select Customer"          
        DisplayMemberPath="CustomerJobDetails" 
        HorizontalContentAlignment="Center"                     
        SelectionChanged="cbo_SelectionChanged" 
        DropDownOpened="cbo_DropDownOpened" 
        DropDownClosed="cbo_DropDownClosed"
        Style="{StaticResource ComboBoxFlatStyle}"
        />
    

    Now, JobsActive should be a public property of the view model that the DataContext for that control. If it isn't, that won't work.

    Since you've got a SelectionChanged event, I also added a SelectedCustomer binding, which would be a property on your view model as well. The Binding will update this both ways: Change it in your viewmodel, and the combobox selection will change. When the user picks a combobox item, the viewmodel's property value will change.

    private JobTicker _selectedCustomer;
    public JobTicker SelectedCustomer {
        get { return _selectedCustomer; }
        set {
            _selectedCustomer = value;
            //  If you're not in C#6, use this instead:
            //OnPropertyChanged("SelectedCustomer");
            OnPropertyChanged(nameof(SelectedCustomer));
        }
    }
    
    //  Implement INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }
    

    If you do want to get this binding working right away without writing a viewmodel, I don't recommend that approach, but it's absolutely doable. There are several answers on StackOverflow that should help with getting that working: WPF Binding Programatically, How to programmatically set data binding using C# xaml.