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 событие и пометить его как не обработанный, чтобы он продолжал подниматься по визуальному дереву, но даже тогда я не уверен, сработает ли это или нет.

Другие вопросы по тегам