ComboBox with ItemTemplate that includes a button

那年仲夏 提交于 2019-12-10 10:19:48

问题


So, lets say I have a ComboBox with a custom data template. One of the items in the data template is a button:

<ComboBox Width="150" ItemsSource="{Binding MyItems}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Button Content="ClickMe" /> 
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

The problem with this is that the button eats the click, and the item does not get selected if the button is selected. This means that the pull-down does not go away, and no item is selected.

I get WHY this is happening.

Is there a way to work around it? Possibly a way to process the button click (I am binding to a command) and tell it to continue up the chain so the combo box can also process the click?

Note: I am seeing my problem in Silverlight, but I am guessing that the exact same behavior can be seen with WPF.


回答1:


Your best bet would probably be to set the SelectedItem in the button's command.




回答2:


OK, I got it figured out. It is a total hack, but it still lets me bind my command to the button and continue to have Combo-box behavior for selecting the item:

<ComboBox x:Name="MyCombo" Width="150" ItemsSource="{Binding MyItems}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <Button Content="ClickMe" Click="Button_Click" /> 
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

And in the code behind:

private void Button_Click(object sender, RoutedEventArgs e)
{
    MyCombo.SelectedItem = (sender as Button).DataContext;
    MyCombo.IsDropDownOpen = false;
}

If I really wanted to, I could bind the SelectedItem and IsDropDownOpen to properties in my ViewModel but I decided against it to keep this behavior as a hack extension of the XAML, in an effort to keep my ViewModel clean.




回答3:


I found another possibility for the MVVM context. I used an derived class for ComboBox and if an item is adden which derives from ButtonBase I attach to the Click event to close the ComboBox.

This works for my project - but just, because the items itself are buttons, it would not work if they just contain buttons as a child element.

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; };
    }
}



回答4:


I don't know if there is a way to do what you want. If you were to put a Button in a ListBox, for example, the same behavior occurs - clicking the Button does not cause its item in the ListBox to be selected. In fact, this is the case for any control in an ItemsControl that supports selection.

You might be able to do something with the Click event and mark it as not handled so that it continues up the visual tree, but even then I'm not sure if that would work or not.



来源:https://stackoverflow.com/questions/883626/combobox-with-itemtemplate-that-includes-a-button

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!