3

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

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

这样做的问题是按钮会吃掉点击,如果选择了按钮,项目不会被选中。这意味着下拉不会消失,并且没有选择任何项目。

我明白为什么会这样。

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

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

4

4 回答 4

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 的 hack 扩展,以保持我的 ViewModel 干净。

于 2009-05-20T18:22:23.947 回答
1

我发现了 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; };
    }
}
于 2012-07-02T11:26:25.100 回答
1

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

于 2009-05-19T23:01:03.717 回答
0

我不知道是否有办法做你想做的事。例如,如果您将 a 放入 aButtonListBox,则会发生相同的行为 - 单击Button不会导致其在 中的项目ListBox被选中。事实上,任何ItemsControl支持选择的控件都是如此。

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

于 2009-05-19T16:12:00.713 回答