带有包含按钮的 ItemTemplate 的 ComboBox

发布于 2024-07-22 09:02:58 字数 556 浏览 11 评论 0原文

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

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

这样做的问题是该按钮会占用点击次数,并且如果选择该按钮,则不会选择该项目。 这意味着下拉菜单不会消失,并且不会选择任何项目。

我明白为什么会发生这种情况。

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

眼睛会笑 2024-07-29 09:02:58

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

<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 干净。

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.

追风人 2024-07-29 09:02:58

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

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

失去的东西太少 2024-07-29 09:02:58

我发现了 MVVM 上下文的另一种可能性。 我为 ComboBox 使用了一个派生类,如果添加了一个派生自 ButtonBase 的项目,我会附加到 Click 事件来关闭 组合框

这适用于我的项目 - 但只是,因为项目本身是按钮,如果它们只包含按钮作为子元素,它就不起作用。

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

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; };
    }
}
双手揣兜 2024-07-29 09:02:58

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文