【问题标题】:How to add an option to selectively remove items from ComboBox?如何添加选项以选择性地从 ComboBox 中删除项目?
【发布时间】:2014-01-13 14:20:12
【问题描述】:

我有一个显示字符串的ComboBox。如何添加从ComboBox 列表中删除某些项目的选项?我试过了:

<ComboBox.ContextMenu>
    <ContextMenu>
        <MenuItem Header="Remove" Click="MenuItem_OnClick"></MenuItem>
    </ContextMenu>
</ComboBox.ContextMenu>

但我不知道如何找到用户选择的项目:

private void MenuItem_OnClick(object sender, RoutedEventArgs e) {
    /* ... ??? ... */
}

我不介意在每个项目旁边放一些图标,单击时会删除其相关项目,但不知道该怎么做..

总结:

这就是我最终解决的方法(The credit belongs to Nawed Nabi Zada, who provided the main idea of "climbing" using the VisualTreeHelper.GetParent(...) to get the ComboBoxItem, in the accepted answer, below

<ComboBox IsEditable="True" Name="RemotePathComboBox" VerticalAlignment="Center"
          SelectionChanged="RemotePathComboBoxOnSelectionChanged"
          Grid.Column="1" Margin="0,6" KeyUp="HostNameOrIPAddress_OnKeyUp">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <DockPanel>
                <Button Click="RemoveRemotePathItem_Click" Margin="5" DockPanel.Dock="Left">
                    <Image Source="{Binding Converter={StaticResource iconExtractor}, ConverterParameter=%WinDir%\\System32\\shell32.dll|131}"/>
                </Button>
                <TextBlock Name="ItemTextBlock" VerticalAlignment="Center" Text="{Binding Path=Path}"></TextBlock>
            </DockPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

代码隐藏:

private void RemoveRemotePathItem_Click(object sender, RoutedEventArgs e) {
    var depObj = sender as DependencyObject;

    while (!(depObj is ComboBoxItem)) {
        if (depObj == null) return;
        depObj = VisualTreeHelper.GetParent(depObj);
    }

    var comboBoxItem = depObj as ComboBoxItem;
    var item = comboBoxItem.Content as RemotePathItem;

    _remotePathsList.Remove(item);
    RemotePathComboBox_SelectIndexWithoutChangingList(0);
}

(The "Icon Extractor" that fetches the icon from the system's DLL is from an old post of mine)

【问题讨论】:

  • 虽然它偏离了您当前的策略,但您可以考虑只处理 DEL 键。
  • @MichaelPerrenoud,它不会很人性化。
  • 使用SelectedItem? ComboBox 上的 ContextMenu 对我来说似乎是错误的......
  • @StefanDenchev,是的,我可以先选择该项目,然后做一些事情(右键单击/单击一些“删除”按钮/等...),但我正在寻找直观的用户的方式 - 这样他就可以一个一个地删除他想要的项目,而不必选择删除 - 选择删除 - 选择删除 - ...
  • 你的意思是右键单击不会选择项目(就像我说的,我永远不会在组合上放置上下文菜单)?

标签: c# wpf xaml visualtreehelper


【解决方案1】:

你也可以这样做:

<Window x:Class="RemoveItemsFromComboBox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <ComboBox x:Name="CbxItems" VerticalAlignment="Top" HorizontalAlignment="Left" Width="250">
        <ComboBox.ContextMenu>
            <ContextMenu>
                <MenuItem x:Name="MenuItem" Header="Delete" Click="MenuItem_OnClick"></MenuItem>
            </ContextMenu>
        </ComboBox.ContextMenu>
        <TextBlock Text="Item 1"/>
        <TextBlock Text="Item 2"/>
        <TextBlock Text="Item 3"/>
        <TextBlock Text="Item 4"/>
    </ComboBox>
</Grid>

public partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
        CbxItems.PreviewMouseRightButtonDown += OnPreviewMouseRightButtonDown;
    }


    private void OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        var comboBoxItem = VisualUpwardSearch(e.OriginalSource as DependencyObject);

        if (comboBoxItem == null) return;
        comboBoxItem.IsSelected = true;
        e.Handled = true;
    }

    private ComboBoxItem VisualUpwardSearch(DependencyObject source)
    {
        while (source != null && !(source is ComboBoxItem))
            source = VisualTreeHelper.GetParent(source);

        return source as ComboBoxItem;
    }

    private void MenuItem_OnClick(object sender, RoutedEventArgs e)
    {
        CbxItems.Items.Remove(CbxItems.SelectedItem);
    }
}

【讨论】:

    【解决方案2】:

    为每个 ComboBoxItem 放置 ContextMenu 而不是 ComboBox 本身:

    <ComboBoxItem.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Remove" Click="MenuItem_OnClick"></MenuItem>
        </ContextMenu>
    </ComboBoxItem.ContextMenu>
    

    您也可以将它放在 DataTemplate 中或从后面的代码生成它,具体取决于您填充 ComboBox 的方式。然后在菜单项的点击事件处理程序中,您可以执行以下操作来让用户选择ComboBoxItem

    private void MenuItem_OnClick(object sender, RoutedEventArgs e)
    {
        var menuItem = (MenuItem)sender;
        var ctxMenu = (ContextMenu)menuItem.Parent;
        var comboBoxItem = (ComboBoxItem) ctxMenu.PlacementTarget;
    }
    

    【讨论】:

      【解决方案3】:

      为了定位组合框项目,您可以在组合框的项目模板中使用复选框,以便用户可以检查他/她要删除的项目。

      如果您的组合框是数据绑定的,那么您将必须过滤组合框的数据源,即在上下文菜单上单击您必须从组合框的数据源中删除用户检查的项目,然后重新绑定组合框数据源。

      如果您没有数据绑定组合框,则在上下文菜单中单击只需循环浏览组合框项目并删除用户选中的项目。

      【讨论】:

      • 我认为问题是如何获取用户想要删除的项目。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      相关资源
      最近更新 更多