Today we are looking into databinding to the ComboBox.SelectedItem
property through a custom dependency property in a UserControl
.
Post 42
But before all that I want to let you all know, this is post #42 on Developers 42. For obvious reasons, this is a special post on my blog. As I started out last year, I didn't have any visitors, but now I average about 1700 visits a month. A large part of these visits come through Google, but a special thanks goes out to Dave Campbell for publishing a lot of my articles on SilverlightCream.com. Through his great efforts of bringing us the latest and greatest on Silverlight, his website is the second greatest referrer, only topped by Google. I won't elaborate any more on this. Stats, highs and lows will all be published in October when the blog celebrates it's first year of existence.
Binding to ComboBox.SelectedItem
through a custom dependency property in a UserControl
, I ran into this building a user control based on the requirement that we need a combo box that includes an edit button next to it when needed and also provides a label when needed. The simplest way to do this (at least as I see it), is through building two UserControl
s. The first combines the ComboBox
with a Button
and the second combines the result with a TextBlock
. Today we want to focus on the first one, which I dubbed ExtendedComboBox
. I wrote the following XAML as a start:
<UserControl
xmlns:input="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Input"
xmlns:inputToolkit="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Input.Toolkit"
x:Class="ExtendedComboBox.ExtendedComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
x:Name="extendedComboBoxControl"
>
<StackPanel x:Name="stackPanel" Orientation="Horizontal" HorizontalAlignment="Stretch">
<ComboBox x:Name="comboBox"
HorizontalAlignment="Stretch"
SelectionChanged="comboBox_SelectionChanged"
>
</ComboBox>
<Button x:Name="editButton" Content="..." Padding="5,0,5,0"
LayoutUpdated="editButton_LayoutUpdated"
Click="editButton_Click"/>
</StackPanel>
</UserControl>
Simple enough. All I had to do now was add some dependency properties to control some functionality and Bob's your uncle, right? Wrong! I will spare you the details on sizing specifics and events, as this is not the focus of this article.
For databinding, I figured I would need to bind to the ItemsSource
and the SelectedItem
properties of the ComboBox
. Here is the code I initially came up with:
publicIEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
comboBox.ItemsSource = value;
}
}
publicstaticreadonlyDependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable),
typeof(ExtendedComboBox), newPropertyMetadata(null));
publicobject SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set
{
SetValue(SelectedItemProperty, value);
comboBox.SelectedItem = SelectedItem;
}
}
publicstaticreadonlyDependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(ExtendedComboBox),
newPropertyMetadata(null));
As you can see, these are standard dependency properties, only I've added a line to assign their values through to the ComboBox
. For the ItemsSource
property this works like a charm, however, for the SelectedItem
property it doesn't.
After struggling with this, building a complete test rig and reading through books worth of blog posts, I finally came up with the following solution. I removed the passing through of the value in the properties setter method and added manual binding for the property in the constructor of the ExtendedCombobox
. Here is my new constructor:
public ExtendedComboBox()
{
InitializeComponent();
Binding selectedItemBinding = newBinding("SelectedItem");
selectedItemBinding.Source = this;
selectedItemBinding.Mode = BindingMode.TwoWay;
comboBox.SetBinding(ComboBox.SelectedItemProperty, selectedItemBinding);
}
This way the ExtendedComboBox
becomes the source of the binding for the ComboBox.SelectedItem
property. After adding this (and obviously also implementing the Equals
and GetHashCode
methods on the business objects involved), it now works like a charm, without having to write any extra code in the modules that use this control.
Please leave me a comment if you have any questions, remarks or if you just want to say hi.