Andre Roque Andre Roque - 2 months ago 10
C# Question

Create UserControl ComboBox with Button

I'm trying to create an UserControl that have a ComboBox with a list of items and then I want to add a button to perform some action.

I have this code:

ComboBoxWithButton XAML:

<ComboBox x:Name="ComboBoxBtn" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0,0,0,-1" Width="100" ItemsSource="{Binding Source}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Content="{Binding }" Width="100" />
<Button Grid.Column="1">Something</Button>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>


ComboBoxWithButton Code:

public ComboBoxWithButton()
{
InitializeComponent();
}


public static readonly DependencyProperty SourceProprety =
DependencyProperty.Register("Source", typeof(ObservableCollection<object>), typeof(ComboBoxWithButton), new PropertyMetadata(null));

public ObservableCollection<object> Source
{
get { return (ObservableCollection<object>)GetValue(ValueProprety); }
set { SetValue(ValueProprety, value); }
}


Then on my Window I call:

<controls:ComboBoxWithButton Source="{Binding SomeCollection}"/>


But the combobox is empty

Answer

Make three changes in your dependency property: Change its type to System.Collections.IEnumerable (non-generic), correct the name of SourceProprety to SourceProperty, and use SourceProperty rather than ValueProperty in your calls to GetValue() and SetValue() (that last bug won't affect the ComboBox, because a Binding will call SetValue() and GetValue() directly, but it's still a bug):

public static readonly DependencyProperty SourceProperty =
     DependencyProperty.Register("Source", 
         typeof(IEnumerable), 
         typeof(ComboBoxWithButton), 
         new PropertyMetadata(null));

public IEnumerable Source
{
    get { return (IEnumerable)GetValue(SourceProperty); }
    set { SetValue(SourceProperty, value); }
}

Your definition of the property required the collection to be of type ObservableCollection<object>. Only object, nothing but object. If you bound ObservableCollection<MyItem> to it, it would fail to populate the ComboBox. ComboBox.ItemsSource is of type System.Collections.IEnumerable (the property is inherited from ItemsControl). Stick with that. It works. Any ObservableCollection of anything can be bound to that. Let the ComboBox figure out the details; that's what it does best.

Next, your binding is looking at the UserControl's DataContext for the Source property, but it's a property of the UserControl itself. Here's how to fix that:

<ComboBox 
    x:Name="ComboBoxBtn" 
    VerticalAlignment="Top" 
    HorizontalAlignment="Left" 
    Margin="0,0,0,-1" 
    Width="100" 
    ItemsSource="{Binding Source, RelativeSource={RelativeSource AncestorType=UserControl}}"
    >

The XAML designer may give you a blue squiggle under the ItemsSource line. Let it moan, it just gets confused sometimes.

Comments