【问题标题】:Finding what was selected in the combobox list using right-click使用右键单击查找在组合框列表中选择的内容
【发布时间】:2016-09-13 23:01:58
【问题描述】:

我正在使用 C# 和 WPF 编写一个 Windows 桌面应用程序。我有一个组合框,用于输入文件路径或从以前使用的文件路径中进行选择。如果文件被删除或用户输入了有效文件但不是所需文件,则列表中的文件可能会变得无效。他们要求一种从组合框下拉列表中删除错误条目的方法。他们想右键单击一个项目并从上下文菜单中选择删除。

<ComboBox x:Name="cbDocket" IsEditable="True">
   <ComboBox.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Remove" Click="cbDocket_MenuItemRemove">/>
        </ContextMenu>
    </ComboBox.ContextMenu>
</ComboBo>

这是最简单的部分。我无法弄清楚的是如何确定他们选择了哪个项目。搜索没有找到任何有效的建议。任何帮助,将不胜感激。有没有另一种更容易的方法来做到这一点?哦,是的,我对 C# 和 WPF 都很陌生。

谢谢,布赖恩

【问题讨论】:

    标签: c# wpf combobox


    【解决方案1】:

    WPF 中的上下文菜单在设计上被严重破坏了,所以大约一半的正常情况下,你所做的任何实际有效的事情都是杂乱无章的。我想出了一些;这是另一个并不是那么笨拙的。

    XAML:

    <ComboBox x:Name="cbDocket" IsEditable="True">
        <ComboBox.Resources>
            <ContextMenu x:Key="ItemMenu">
                <MenuItem Header="Remove" Click="MenuItem_Click" />
            </ContextMenu>
        </ComboBox.Resources>
    
        <!-- Some arbitrary random junk to display in the ComboBox -->
        <TextBlock Text="Foo" />
        <TextBlock Text="Bar" />
        <!-- End of arbitrary random junk -->
    
        <ComboBox.ItemContainerStyle>
            <Style TargetType="{x:Type ComboBoxItem}">
                <Setter 
                    Property="ContextMenu" 
                    Value="{StaticResource ItemMenu}" 
                    />
            </Style>
        </ComboBox.ItemContainerStyle>
    </ComboBox>
    

    后面的代码:

    private void MenuItem_Click(object sender, RoutedEventArgs e)
    {
        //  This needs some null checking and a try catch, but this is the guts of it. 
    
        //  sender should be the MenuItem as well
        var menuItem = e.OriginalSource as MenuItem;
    
        //  Since we used ItemContainerStyle to give each ComboBoxItem its own 
        //  personal ContextMenu, each ContextMenu will have its PlacementTarget
        //  set to the ComboBoxItem that owns it. 
        var cbItem = (menuItem.Parent as ContextMenu).PlacementTarget as ComboBoxItem;
    
        //  ???
        //var dataItem = cbItem.DataContext;
    }
    

    你没有提到你是如何填充组合框的,所以我不知道你是否在项目上设置了 DataContext 或什么。但是一旦你有了ComboBoxItem,你就可以到达那里。

    【讨论】:

    • 有效!该框由用户键入的内容或使用 OpenFileDialog 的选择按钮填充。不了解DataContext。这是一个我还没学过的高级主题。
    【解决方案2】:

    添加一个事件以在下拉菜单打开时跟踪鼠标移动,并在单击删除时使用该事件。

        <ComboBox x:Name="cbDocket" HorizontalAlignment="Left" Margin="33,30,0,269" Width="124" IsEditable="True">
            <ComboBox.ContextMenu>
                <ContextMenu Name="Menu">
                    <MenuItem Header="Remove" Click="cbDocket_MenuItemRemove"/>
                </ContextMenu>
            </ComboBox.ContextMenu>
            <ComboBox.ItemContainerStyle>
                <Style TargetType="{x:Type ComboBoxItem}">
                    <EventSetter Event="MouseMove" Handler="cbDocket_OnMouseMove" />
                </Style>
            </ComboBox.ItemContainerStyle> 
    </ComboBox>
    

    后面的代码:

    ComboBoxItem cbiSelected = null;
    
    private void cbDocket_MenuItemRemove(object sender, RoutedEventArgs e)
    {
        cbDocket.Items.Remove(cbiSelected);
    }
    
    private void cbDocket_OnMouseMove(object sender, MouseEventArgs e)
    {
        ComboBoxItem cbiHover = sender as ComboBoxItem;
        if (cbiHover.IsHighlighted)
        {//Verify the item is highlighted
            cbiSelected = cbiHover;
        }
    }
    

    【讨论】:

      【解决方案3】:

      有几种方法可以做到这一点。由于您使用的是Click 事件处理程序,因此事件的source 始终是被单击的项目。例如:

      Xaml:

      <ComboBox x:Name="cbDocket" IsEditable="True">
          <ComboBox.ContextMenu>
              <ContextMenu>
                  <MenuItem Header="Remove" Click="cbDocket_MenuItemRemove">/>
              </ContextMenu>
          </ComboBox.ContextMenu>
      </ComboBo>
      

      Xaml.cs:

      private void cbDocket_MenuItemRemove(object source, EventArgs args)
      {
          // Source is your item:
          cbDocekt.Items.Remove(cbDocket.SelectedItem);
      }
      

      当然你总是可以获取选中项,甚至可以使用SelectedItem属性改变组合框中的选中项。

      我假设您正在使用后面的代码来执行此操作。

      【讨论】:

      • 当我尝试这样做时,我发现sourceMenuItem,而((source as MenuItem).Parent as ContextMenu).PlacementTargetComboBox。这不是你测试时看到的吗?
      • sourceMenuItem,这是我从给出的示例代码中所期望的。 ComboBox 在原始代码中被命名为:cbDocket。因此,OP 可以通过您到达 ComboBox 的路径,或者直接访问它。给这只猫剥皮的方法还有很多,但我选择让它尽可能接近提供的代码。
      • 在回到我的答案并更详细地查看之后,我错过了一个重要的细节:OP 想要删除选定的项目。这真是漫长的一天......
      • 我相信他希望他们能够点击下拉列表中的任意项目,而不仅仅是选定的项目。事实上,我应该检查我的答案是否适用于所选项目...
      • 哎呀。这是一个可编辑的组合框;在它关闭时单击它会得到 TextBox contxt 菜单,当然
      【解决方案4】:

      使用以下程序代码,您可以将上下文菜单添加到组合框。在此上下文菜单中,可以删除组合框的单个项目或所有项目。

      private ComboBox FolderComboBox;
      private ContextMenu FolderHistoryContextMenu;
      
      ...    
      
      private void CreateFolderHistoryContextMenu()
      {
        MenuItem RemoveFolderMenuItem, RemoveAllFoldersMenuItem;
      
        FolderHistoryContextMenu = new ContextMenu();
        RemoveFolderMenuItem = new MenuItem();
        RemoveFolderMenuItem.Header = "Remove folder";
        RemoveFolderMenuItem.Click += new RoutedEventHandler(RemoveFolderMenuItem_Click);
        FolderHistoryContextMenu.Items.Add(RemoveFolderMenuItem);
        RemoveAllFoldersMenuItem = new MenuItem();
        RemoveAllFoldersMenuItem.Header = "Remove all folders";
        RemoveAllFoldersMenuItem.Click += new RoutedEventHandler(RemoveAllFoldersMenuItem_Click);
        FolderHistoryContextMenu.Items.Add(RemoveAllFoldersMenuItem);
      
        // The context menu is assigned to each item in the list of the combo box and not to the combo box itself.
        if (FolderComboBox.ItemContainerStyle == null)
        {
          FolderComboBox.ItemContainerStyle = new Style(typeof(ComboBoxItem));
        }
        FolderComboBox.ItemContainerStyle.Setters.Add(new Setter(ContextMenuProperty, FolderHistoryContextMenu));
      }
      
      
      private void RemoveFolderMenuItem_Click(object sender, RoutedEventArgs e)
      {
        ComboBoxItem ClickedComboBoxItem = FolderHistoryContextMenu.PlacementTarget as ComboBoxItem;
        if (ClickedComboBoxItem != null)
        {
          object ComboBoxDataItem = ClickedComboBoxItem.DataContext;
          FolderComboBox.Items.Remove(ComboBoxDataItem);
        }
      }
      
      
      private void RemoveAllFoldersMenuItem_Click(object sender, RoutedEventArgs e)
      {
        FolderComboBox.Items.Clear();
      }
      

      【讨论】:

        猜你喜欢
        • 2012-03-02
        • 2012-03-02
        • 1970-01-01
        • 1970-01-01
        • 2013-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多