【问题标题】:ComboBox with ItemTemplate that includes a button带有包含按钮的 ItemTemplate 的 ComboBox
【发布时间】:2009-05-19 16:00:47
【问题描述】:

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

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

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

我明白为什么会这样。

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

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

【问题讨论】:

    标签: wpf silverlight combobox itemtemplate


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 是的,我考虑过,但这样做并不会消除组合框创建的下拉菜单。
      • ComboBoxes 上还有一个 IsOpen(或非常相似的)属性,您可以将其设置为 False。您还可以在按钮上设置 Focusable="False" 并让它自动发生。
      • 是的,它最终成为了两者的结合。请参阅我的答案以获得完整的解决方案,但我想给你信用分,所以我将你的答案标记为正确。
      【解决方案3】:

      我发现了 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; };
          }
      }
      

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 2023-03-22
          • 2012-02-17
          • 2020-04-05
          • 2014-12-05
          • 1970-01-01
          • 1970-01-01
          • 2018-06-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多