Reputation: 527
Consider a ListBox that may not be completely filled with ListBoxItems at run time. I want to customize the ContextMenu for that ListBox depending on whether the user right clicks on one of the ListBoxItems or on the blank space where no items exist.
The problem I'm having is that in the latter case, no ListBox events are fired, only the ContextMenuOpening event is fired. And from that event I cannot figure out how to ascertain whether the user right clicked on an existing ListBoxItem or not.
I have looked at all the ListBox properties and events but canot come up with an approach that differentiates these two cases. I've considered using Style Triggers but, again, the core problem is that a Right-Click in the blank space does not trigger any ListBox events. I've also reviewed the links that SO suggests but none speak to this question.
How can this be done?
Upvotes: 0
Views: 1272
Reputation: 430
Here is a more concise approach to define two different ContextMenu
for ListBox
and its ListBoxItem
without the need to any code-behind checking, it works like a charm:
<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>
If you want to modify contents of ListBoxItem.ContextMenu
dynamically based on selected item you can hook up a handler for the ContextMenu.Opened
event and in that handler you check the selected item and add new MenuItem
Collection to your ContextMenu
in code.
Note that these two ContextMenu
s will be displayed only inside this ListBox
thats because they are defined in its ListBox.Resources
.
Upvotes: 1
Reputation: 946
Maybe I didn't get your intention: You can define different ContextMenu
either in XAML
or Code-behind
like this:
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>
Code-behind:
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
}
}
}
Upvotes: 0
Reputation: 527
I devised a solution which is not pretty but does work. Basically, whenever the ListBox loses focus, I force it to have nothing selected by setting
ListBox.SelectedIndex = -1
Now, in the ContextMenuOpening event when the focus is back to the ListBox, it is possible to get the get the ListBox.SelectedIndex and if it is -1 then the user clicked in the blank portion of the ListBox otherwise a ListBoxItem was clicked on.
Coding this logic is straightforward.
Upvotes: 0