2017-10-14 86 views
0

考虑一个ListBox,在运行时可能不会完全用ListBoxItems填充。我想为该ListBox自定义ContextMenu,具体取决于用户是否右键单击其中一个ListBoxItem或没有项目存在的空白区域。如何为wpf列表框自定义ContextMenu

我遇到的问题是,在后一种情况下,不会触发ListBox事件,只会触发ContextMenuOpening事件。从那个事件我不知道如何确定用户是否右键单击现有的ListBoxItem或不。

我已经看过所有的ListBox属性和事件,但canot想出了一种方法来区分这两种情况。我曾考虑过使用样式触发器,但是,核心问题是空白区域的右键单击不会触发任何ListBox事件。我也回顾了SO建议的链接,但没有人会提到这个问题。

这怎么办?

+0

请给出一些代码来解释你的问题更清楚吗? – Iron

+0

你能展示你使用的逻辑以及你的逻辑与哪些事件相连接吗?您可以在资源中创建两个ContextMenu,并在ListBox.ContextMenu和ListBoxItem.ContextMenu中使用它们。 – Redouane

+0

@Iron它不是一个编码问题,而是一个概念性问题:如何检测在部分填充的列表框中点击右键单击的内容。如果我有任何代码,我会显示它。但请参阅下面的解决方案。 – SezMe

回答

0

我设计了一个解决方案,但并不漂亮,但工作。基本上,只要在列表框失去焦点,我强迫它什么都没有通过设置选择现在

ListBox.SelectedIndex = -1 

,在事件的ContextMenuOpening当焦点返回到列表框,就可以得到得到ListBox.SelectedIndex如果它是-1,那么用户点击ListBox的空白部分,否则点击一个ListBoxItem。

编码这个逻辑很简单。

0

也许我还不知道你的意图:您可以定义不同ContextMenu无论是在XAMLCode-behind这样的:

XAML:

<ListBox PreviewMouseDown="ListBox_PreviewMouseDown"> 
    <ListBox.ItemContainerStyle> 
     <Style TargetType="{x:Type ListBoxItem}"> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="{x:Type ListBoxItem}"> 
         <ContentPresenter> 
          <ContentPresenter.ContextMenu> 
           <ContextMenu> 
            <MenuItem Header="ListBoxItem"></MenuItem> 
            <MenuItem Header="ListBoxItem"></MenuItem> 
            <MenuItem Header="ListBoxItem"></MenuItem> 
           </ContextMenu> 
          </ContentPresenter.ContextMenu> 
         </ContentPresenter> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ListBox.ItemContainerStyle> 
    <ListBoxItem>Item1</ListBoxItem> 
    <ListBoxItem>Item2</ListBoxItem> 
    <ListBoxItem>Item2</ListBoxItem> 
    <ListBoxItem>Item2</ListBoxItem> 
    <ListBox.ContextMenu> 
     <ContextMenu> 
      <MenuItem Header="ListBox"></MenuItem> 
      <MenuItem Header="ListBox"></MenuItem> 
      <MenuItem Header="ListBox"></MenuItem> 
     </ContextMenu> 
    </ListBox.ContextMenu> 
</ListBox> 

代码隐藏:

private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e) 
{ 
    if(e.ChangedButton == MouseButton.Right) 
    { 
     var listBoxItem = e.Source as ListBoxItem; 
     if (listBoxItem != null) 
     { 
      // clicked on ListBoxItem, customize the ContextMenu 
     } 

     var listBox = e.Source as ListBox; 
     if (listBox != null) 
     { 
      // clicked on ListBox, customize the ContextMenu 
     } 
    } 
} 
0

下面是一个更简洁的方法来定义ListBox和的两个不同的,无需任何代码隐藏检查,它就像一个魅力:

<ListBox ContextMenu="{StaticResource ListContextMenu}"> 
    <ListBox.Resources> 
     <!-- Context Menu when right click on selected List Item --> 
     <ContextMenu x:Key="ItemContextMenu"> 
      <MenuItem Header="Eat"></MenuItem> 
      <MenuItem Header="Delete"></MenuItem> 
      <Separator></Separator> 
      <MenuItem Header="Send To Friend"></MenuItem> 
     </ContextMenu> 
     <!-- Context Menu when right click on listbox space --> 
     <ContextMenu x:Key="ListContextMenu"> 
      <MenuItem Header="Save Fruits"></MenuItem> 
      <MenuItem Header="Add Or Remove Fruits"></MenuItem> 
     </ContextMenu> 
     <!-- Applying Context Menu to ListBoxItem with Style --> 
     <Style TargetType="{x:Type ListBoxItem}"> 
      <Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}"> 
      </Setter> 
     </Style> 
    </ListBox.Resources> 

    <ListBox.ContextMenu> 
     <Binding Source="{StaticResource ListContextMenu}"></Binding> 
    </ListBox.ContextMenu> 


    <ListBoxItem>Banana</ListBoxItem> 
    <ListBoxItem>Apple</ListBoxItem> 
    <ListBoxItem>Orange</ListBoxItem> 
</ListBox> 

如果你想修改动态地根据所选项目的ListBoxItem.ContextMenu内容,你可以挂钩的处理程序ContextMenu.Opened事件,并在处理程序检查所选项目并在代码中将新的MenuItem集合添加到您的ContextMenu

请注意,这两个ContextMenu将仅在此ListBox内显示,因为它们在其​​中定义。