ComboBox с ItemTemplate, который включает в себя кнопку
Итак, допустим, у меня есть ComboBox с пользовательским шаблоном данных. Одним из элементов в шаблоне данных является кнопка:
<ComboBox Width="150" ItemsSource="{Binding MyItems}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Button Content="ClickMe" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Проблема в том, что кнопка съедает щелчок, и элемент не выбирается, если кнопка выбрана. Это означает, что выпадающий список не исчезнет, и ни один элемент не будет выбран.
Я понимаю, почему это происходит.
Есть ли способ обойти это? Возможно, способ обработать щелчок кнопки (я привязан к команде) и сказать ему, чтобы он продолжал цепочку, чтобы поле со списком могло также обрабатывать щелчок?
Примечание. Я вижу свою проблему в Silverlight, но предполагаю, что точно такое же поведение можно увидеть и в WPF.
4 ответа
Лучше всего было бы установить SelectedItem в команде кнопки.
Хорошо, я понял это. Это полный взлом, но он по-прежнему позволяет мне привязать мою команду к кнопке и по-прежнему иметь поведение Combo-box для выбора элемента:
<ComboBox x:Name="MyCombo" Width="150" ItemsSource="{Binding MyItems}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Button Content="ClickMe" Click="Button_Click" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
И в коде позади:
private void Button_Click(object sender, RoutedEventArgs e)
{
MyCombo.SelectedItem = (sender as Button).DataContext;
MyCombo.IsDropDownOpen = false;
}
Если бы я действительно хотел, я мог бы привязать SelectedItem и IsDropDownOpen к свойствам в моей ViewModel, но я решил не использовать это поведение как расширение для взлома XAML, чтобы сохранить свою ViewModel в чистоте.
Я нашел другую возможность для контекста MVVM. Я использовал производный класс для ComboBox
и если элемент является адден, который происходит от ButtonBase
Я прикрепляю к Click
событие, чтобы закрыть ComboBox
,
Это работает для моего проекта - но только потому, что сами элементы являются кнопками, это не будет работать, если они просто содержат кнопки как дочерний элемент.
public class MyComboBox : ComboBox
{
public MyComboBox()
{
// use Loaded event to modify inital items.
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
if (Items != null)
{
foreach (var item in Items)
{
var button = item as ButtonBase;
if (button != null)
{
ModifyButtonItem(button);
}
}
}
}
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);
// Check added items. If an item is a button, modify the button.
if (e.NewItems != null)
{
foreach (var item in e.NewItems)
{
var button = item as ButtonBase;
if (button != null)
{
ModifyButtonItem(button);
}
}
}
}
private void ModifyButtonItem(ButtonBase button)
{
button.Click += (sender, args) => { IsDropDownOpen = false; };
}
}
Я не знаю, есть ли способ сделать то, что вы хотите. Если бы вы должны были поставить Button
в ListBox
например, происходит то же самое поведение - щелкнув Button
не вызывает его пункт в ListBox
быть выбранным. На самом деле, это так для любого контроля в ItemsControl
это поддерживает выбор.
Вы могли бы сделать что-то с Click
событие и пометить его как не обработанный, чтобы он продолжал подниматься по визуальному дереву, но даже тогда я не уверен, сработает ли это или нет.