I’d like to include a few Button
inside a ComboBox
directly in XAML (not populated by a view model):
<ComboBox>
<Button Command="{Binding PerformAction1}" Content="Action1" />
<Button Command="{Binding PerformAction2}" Content="Action2" />
</ComboBox>
So, the ComboBoxItem
correspond to a Button
in order to directly execute a Command
when clicked.
1st issue: When I click a button, the ComboBoxItem
is not selected. I can change the ItemTemplate
in order to add a Button_Click
callback.
<ComboBox.ItemTemplate>
<DataTemplate>
<Button Click="Button_Click" Content="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
var content = button.Content as Button; // Gets the the actual button within the button from the template.
//content.Command.Execute(null); // content.Command is null.
var cbi = UIHelpers.FindParent<ComboBoxItem>(button);
cbi.IsSelected = true;
}
2nd issue: The Command
binding is not executed from XAML and it seems that I can’t get it from the code-behind.
Does someone have an idea how to solve it?
8
I’ll write right away that I agree with Clemens and ASh – the solution you’ve chosen is terrible. (See my reply to ASh’ comment)
But for educational purposes I’ll give an explanation and show a solution.
The button intercepts MouseLeftButtonDown/Up
events, marks them as handled Handled= true
, and raises the Click
event. Since MouseLeftButtonDown/Up
events have already been handled, the parent elements (including ComboBoxItem) “don’t see” them.
Your use of the Click event is one of the solutions to this problem.
Using a nested button is definitely excessive.
It would also be more optimal to transfer most of the logic to XAML, but only do the most necessary in code.
An example of implementation:
<ComboBox>
<Button Command="{Binding PerformAction1}" Content="Action1"
Click="OnSelectedItem"
Tag="{Binding SelectedItem, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Selector}}}"/>
<Button Command="{Binding PerformAction2}" Content="Action2"
Click="OnSelectedItem"
Tag="{Binding SelectedItem, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Selector}}}"/>
</ComboBox>
<x:Code>
<![CDATA[
private void OnSelectedItem(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
btn.Tag = btn;
}
]]>
</x:Code>
You can also use interception of the bubble-event at the ComboBox level. This will simplify the XAML a little.
<ComboBox ButtonBase.Click="OnBubbleСlick">
<Button Command="{Binding PerformAction1}" Content="Action1"/>
<Button Command="{Binding PerformAction2}" Content="Action2"/>
</ComboBox>
<x:Code>
<![CDATA[
private void OnBubbleСlick(object sender, RoutedEventArgs e)
{
((Selector)sender).SelectedItem = e.OriginalSource;
}
]]>
</x:Code>