Xceed’s WPF Toolkit is a popular extension to the standard components offered by Microsoft’s WPF. One fancy control that I have been using lately is the CheckComboBox, which is a ComboBox that show’s a list of items and checkboxes when opened and a list of selected items when closed. For example, it is great for selecting filtering options in smaller sets.
However, it took me a little bit to get it all up and running with DataBinding. I am going to walk you throught it. For reference, I’m starting with a .NET 4.6.1 WPF App in Visual Studio 2017.
First you have to install Extended.Wpf.Toolkit, which I am doing via VS’s built-in package manager. To actually use the control, I am adding an XML namespace into my MainWindow’s XAML:
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Then I’m adding the control in a simple StackPanel, while already adding DataBindings:
<xctk:CheckComboBox ItemsSource="{Binding Path=Options}" DisplayMemberPath="Name" SelectedMemberPath="Selected"/>
This means that my control will look at a collection named “Options” in my view-model, using it’s elements “Name” property for display and its “Selected” property for the checkmark. If you run the program at this point, you should be able to see an empty CheckComboBox, albeit badly layouted.
Now it’s time to create the view model. Let’s start with a small class-let to represent our items:
class Item { public string Name { get; set; } public bool Selected { get; set; } }
As you can see, the names match what we set for DisplayMemberPath
and SelectedMemberPath
in the XAML. Now for the ViewModel
class:
class ViewModel { public ViewModel() { var languages = new string[] { "C", "C#", "C++", "D", "Java", "Rust", "Python", "ES6" }; Options = new List<Item>(); foreach (var language in languages) { Options.Add(new Item { Name = language, Selected = true }); } } public List<Item> Options { get; set; } }
If you run it at this point, you should be able to see an all-selected list of programming languages in the drop-down. But it is lacking a crucial detail: it is not observable, meaning the component will not be notified if the data in the view-model is changed by other means. To make sure that it can, the Item list and the Item have to implement the INotifyPropertyChanged interface. To do that, you have to fire a specific event whenever a property changes with the name of that property in it.
Let’s do that for the Item first:
class Item : INotifyPropertyChanged { private bool _selected; private string _name; public string Name { get => _name; set { _name = value; EmitChange(nameof(Name)); } } public bool Selected { get => _selected; set { _selected = value; EmitChange(nameof(Selected)); } } private void EmitChange(params string[] names) { if (PropertyChanged == null) return; foreach (var name in names) PropertyChanged(this, new PropertyChangedEventArgs(name)); } public event PropertyChangedEventHandler PropertyChanged; }
That got bigger! But it’s not a lot of meat really. For the Item list, we can just use ObservableCollection instead of List:
public ObservableCollection<Item> Options {get; set;}
That’s it. Two-way data binding set-up for the item collection, and you can now change the view-model and have the component react to it, but also react to changes from the component by hooking into the property-set
functions.
Now you could also implement INotifyPropertyChanged for the ViewModel, if you intend to swap in new ObserableCollection
s, but that is not necessary for this example.
Modifying Item.Selected does not update the View.