Как добавить опцию для выборочного удаления элементов из ComboBox?

У меня есть ComboBox это отображает строки. Как я могу добавить опцию, чтобы удалить некоторые элементы из ComboBox список? Я старался:

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

Но я не знаю, как найти элемент, который выбрал пользователь:

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

Я не против поставить значок рядом с каждым элементом, который удаляет связанный элемент при нажатии, но не знаю, как это сделать.

Резюме:

Вот как я решил это, наконец ( кредит принадлежит Nawed Nabi Zada , который представил основную идею "лазания" с помощью VisualTreeHelper.GetParent(...) чтобы получить ComboBoxItem , в принятом ответе, ниже)

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

("Icon Extractor", который выбирает значок из системной DLL, взят из моего старого поста)

3 ответа

Решение

Вы также можете сделать это следующим образом:

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

Поместите это ContextMenu для каждого ComboBoxItem вместо самого 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;
}

Чтобы найти элементы списка, вы можете использовать флажок в шаблоне элементов списка, чтобы пользователь мог проверить элементы, которые он / она хочет удалить.

Если ваш комбинированный список привязан к данным, вам придется отфильтровать источник данных вашего комбинированного списка, т. Е. При щелчке контекстного меню вам придется удалить элементы, проверенные пользователем, из источника данных вашего комбинированного списка, а затем повторно связать комбинированный список с источником данных.

Если у вас нет связанного списка данных с привязкой к данным, то в контекстном меню щелкните просто циклически переберите элементы комбинированного списка и удалите элементы, которые были проверены пользователем.

Другие вопросы по тегам