代码之家  ›  专栏  ›  技术社区  ›  Brian Genisio

带有包含按钮的ItemTemplate的组合框

  •  3
  • Brian Genisio  · 技术社区  · 15 年前

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

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

    这样做的问题是,按钮会吞噬单击,如果选择了按钮,则项目不会被选中。这意味着下拉列表不会消失,并且不会选择任何项目。

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

    4 回复  |  直到 15 年前
        1
  •  8
  •   Brian Genisio    15 年前

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

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

        2
  •  1
  •   Bryan Anderson    15 年前

        3
  •  1
  •   MatthiasG    12 年前

    我发现了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; };
        }
    }
    
        4
  •  0
  •   Andy    15 年前

    我不知道是否有办法做你想做的事。如果你把 Button 在一个 ListBox ,例如,发生相同的行为-单击 不会导致其项处于 列表框 待选择。事实上,任何控制都是如此 ItemsControl 它支持选择。

    你也许可以用这个做点什么 Click 事件并将其标记为未处理,以便它继续在可视化树上运行,但即使如此,我也不确定这是否有效。