带有ItemTemplate的ComboBox,包含一个按钮

时间:2009-05-19 16:00:48

标签: wpf silverlight combobox itemtemplate

所以,假设我有一个带有自定义数据模板的ComboBox。数据模板中的一个项目是按钮:

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

这个问题是按钮会点击,如果选择按钮,项目就不会被选中。这意味着下拉菜单不会消失,也不会选择任何项目。

我知道为什么会发生这种情况。

有办法解决这个问题吗?可能是一种处理按钮单击的方法(我绑定到一个命令)并告诉它继续向上链,这样组合框也可以处理点击?

注意:我在Silverlight中看到了我的问题,但我猜测WPF可以看到完全相同的行为。

4 个答案:

答案 0 :(得分:8)

好的,我明白了。这是一个完全黑客攻击,但它仍然允许我将命令绑定到按钮并继续使用组合框行为来选择项目:

<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清洁。

答案 1 :(得分:1)

您最好的选择可能是在按钮的命令中设置SelectedItem。

答案 2 :(得分:1)

我发现了MVVM上下文的另一种可能性。我使用了ComboBox的派生类,如果某个项是adden,派生自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; };
    }
}

答案 3 :(得分:0)

我不知道是否有办法做你想做的事。例如,如果您在Button中放置ListBox,则会出现相同的行为 - 点击Button不会导致ListBox中的项目被选中。实际上,支持选择的ItemsControl中的任何控件都是这种情况。

您可以对Click事件执行某些操作并将其标记为未处理,以便它继续显示在可视树中,但即便如此,我也不确定这是否有效。