Context Menu Item for ListBox in WPF - c#

I want to display ContextMenu on right click of ListBoxItems in WPF. I tried below code, but ContextMenu is displaying where ListBoxItems are not there also. What I want is to display ContextMenu only on the right click of only ListBoxItems.
<Grid>
<ListBox x:Name="listofConnectedItems" Grid.Column="0" Grid.Row="0" ItemsSource="{Binding MyItems}" MouseRightButtonDown="listofConnectedItems_MouseRightButtonDown" ContextMenuOpening="listofConnectedItems_ContextMenuOpening" >
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="10">
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="_Start" Click="MenuItemStart_Click" />
<MenuItem Header="Sto_p" Click="MenuItemStop_Click" />
<MenuItem Header="_Clear" Click="MenuItemClear_Click" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</Grid>
`
Here I attached the screenshot.
Can anybody Please get me through this. Thanks in advance

It should be in IntemContainerStyle:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Open" />
<MenuItem Header="Edit" Command="Binding
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>

I think the problem is that You didn't specified height and width of list box so it automaticaly scales to the window size. So technically Your code is working correctly but listbox is everywhere.
try with something like
<ListBox x:Name="listofConnectedItems" Grid.Column="0" Grid.Row="0" BorderThickness="5" Width="200" Height="200"...
and then rightclick outside the listbox

Related

Binding cannot find source when trying to access the datacontext of a custom listview contextmenu

I got a very similar problem with ContextMenu for ListViewItem only but the solution doesn't seem to work in my case.
<GroupBox Header="PlayOffs" Grid.Row="2" Grid.Column="0">
<StackPanel Orientation="Vertical" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ListView Grid.Column="0" ItemsSource="{Binding PlayoffSeries}" ItemTemplate="{StaticResource SeriesTemplate}">
<ListView.Resources>
<ContextMenu x:Key="cm">
<MenuItem Header="SetLive" Click="SetSeriesLive"/>
<MenuItem Header="Start" IsEnabled="{Binding Path=DataContext.CanStart, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListView}}" Click="StartSeries"/>
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="ContextMenu" Value="{StaticResource cm}"/>
<EventSetter Event="MouseDoubleClick" Handler="HandleDoubleClick" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</ScrollViewer>
</StackPanel>
</GroupBox>
I get an error for the IsEnabled binding of the MenuItem Start saying Cannot find source:RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ListView',AncestorLevel='1'
The click command works like a charm, essentially what I want to do is to bind the IsEnabled property of the menuitem to the CanStart property of the underlying datacontext provided from the listviewItem.
I'm a dumdum. I just tried with AncestorType=ContextMenu and it seems to be working like a charm. Still not entirely sure why the first solution worked for the other question though. I suppose its related to the datamodel bound to the listview.

C# WPF ContextMenu: MenuItem does not react to click

I have a C# WPF-Application. In the XAML i have a Datagrid, to which I have added a ContextMenu, that looks like this:
<DataGrid.ContextMenu>
<ContextMenu ItemsSource="{Binding Categories}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Name}" Background="{Binding Brush}" Click="MenuItem_Click" Tag="{Binding Id}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</DataGrid.ContextMenu>
When using the application it looks like this: http://imgur.com/3UTj1Xd
The problem is, that when clicking the color part of the box (which I'm guessing is part of some internal grid) the MenuItem_Click event is fired. However, when I'm clicking on the grey part of the MenuItem the click event is not fired. Does anyone know why it behaves this way? And is there a way to fix this?
Additionally, it would be great to be able to color the whole menu item, not just the small box inside. Is there a way to do this?
You could try to decrease the Padding of the ContextMenu and the BorderThickess of the MenuItems:
<DataGrid.ContextMenu>
<ContextMenu ItemsSource="{Binding Categories}" Padding="0">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Name}" Background="{Binding Brush}" Click="MenuItem_Click" Tag="{Binding Id}"
BorderThickness="0"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</DataGrid.ContextMenu>
Or
<DataGrid.ContextMenu>
<ContextMenu ItemsSource="{Binding Categories}" Padding="0">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Name}" />
<Setter Property="Tag" Value="{Binding Id}" />
<Setter Property="Background" Value="{Binding Brush}" />
<EventSetter Event="Click" Handler="MenuItem_Click" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</DataGrid.ContextMenu>

Hide ContextMenu when Menu has no items

I have created a ContextMenu with a Menu inside it. The Menu doesn't always have items. When there are no items I want to hide the ContextMenu.
Relevant code in my style (generic.xaml)
<Grid.ContextMenu>
<ContextMenu Margin="10,10,0,13" Name="ContextMenu" HorizontalAlignment="Left" VerticalAlignment="Top" IsOpen="False">
<Menu>
<Menu.ItemsSource>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="ChildCommands"/>
</Menu.ItemsSource>
<Menu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="MenuItem.Header" Value="{Binding Command.Text}"/>
<Setter Property="MenuItem.IsEnabled" Value="False"/>
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</Menu.ItemsPanel>
</Menu>
</ContextMenu>
</Grid.ContextMenu>
How can I hide the ContextMenu when there are no menuitems inside it?
EDIT : I fixed it by changing the Menu tags to ContextMenu tags.
Use the visibility property by the context menu. Too hide the context menu bind the menuitemscount and use a converter to convert the Count to the visibility enum.
I changed the Menu tags to ContextMenu tags and it works now. The ContextMenu is only visible when there are items in it.
Code:
<Grid.ContextMenu>
<ContextMenu Margin="10,10,0,13" Name="ContextMenu" HorizontalAlignment="Left" VerticalAlignment="Top" IsOpen="False">
<ContextMenu.ItemsSource>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="ChildCommands"/>
</ContextMenu.ItemsSource>
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="MenuItem.Header" Value="{Binding Command.Text}"/>
<Setter Property="MenuItem.IsEnabled" Value="False"/>
</Style>
</ContextMenu.ItemContainerStyle>
<ContextMenu.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ContextMenu.ItemsPanel>
</ContextMenu>
</Grid.ContextMenu>

WPF "static" binding in a List

I have a problem with a binding in a List.
I have a List of objects. This List is bound to a ListBox. Of every object in my List I can open a ContextMenu:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First" IsEnabled="{Binding FirstEnabled}"/>
<MenuItem Header="Second" IsEnabled="{Binding SecondEnable}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
In the code like this my objects in the list having the two booleans to bind. Now I want to bind this two booleans not to the objects. I want to bind it "static" to my DataContext. This is not working like this and I have no idea how to realize it.
I googled a lot but found nothing helpful ...
Thanks for helping!
Since, ContextMenu applies to ListBoxItem it will have its DataContext value and ListBoxItem will be its PlacementTarget. So if you want to bind to property of ListBox.DataContext you need to pass current ListBox.DataContext as, for example, Tag to ListBoxItem and then you need to refer to it from ContextMenu via its PlacementTarget. It's all because ContextMenu uses Popup which creates its own visual tree so simple RelativeSource/ElementName binding won't work
<Style TargetType="ListBoxItem">
<Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}}, Path=DataContext}"/>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First" IsEnabled="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.Tag.FirstEnabled}"/>
<MenuItem Header="Second" IsEnabled="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget.Tag.SecondEnable}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
You can reference every datacontext with the ElementName Syntax:
<ListBox x:Name="myListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First" IsEnabled="{Binding Path=DataContext.FirstEnabled, ElementName=myListBox}"/>
<MenuItem Header="Second" IsEnabled="{Binding Path=DataContext.SecondEnable, ElementName=myListBox}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
With this syntax you use the DataContext of your ListBox and not from the ListItem.

Connect handler to ContextMenu in "Style" section

I need to create structure of ContextMenu in runtime, because existence of MenuItem's of the menu is based on many factors. And I try add handler to ContextMenuOpening event this way:
XAML
<TreeView x:Name="ArticlesTreeView" Grid.Column="0" AllowDrop="True">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ContextMenuService.ShowOnDisabled" Value="True" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu Opened="ContextMenu_OnOpened">
<MenuItem Header="First item"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
This code throws XamlParseException on <ContextMenu Opened="ContextMenu_OnOpened"> line. Can I solve issue in another way?
UPD I find that to me it is necessary not ContextMenuOpening and Opened event. I corrected upper code.
Try creating your ContextMenu on your ItemTemplate of the treeview. Try the below code (it is not complete but i hope you get the idea)
<TreeView .....>
<TreeView.ItemTemplate>
<DataTemplate>
<ContentControl>
<ContentControl.ContextMenu>
<ContextMenu ContextMenuOpening="ContextMenu_OnContextMenuOpening">
<MenuItem Header="First item"></MenuItem>
</ContextMenu>
</ContentControl.ContextMenu>
---------Your Item Template here
</ContentControl>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Your question is already answered here.
Placing event handlers in event setter did the work.
<TreeView x:Name="ArticlesTreeView" AllowDrop="True">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ContextMenuService.ShowOnDisabled" Value="True" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="First item">
<MenuItem.Style>
<Style TargetType="MenuItem">
<EventSetter Event="Click" Handler="ContextMenu_ContextMenuOpening_1"></EventSetter>
</Style>
</MenuItem.Style>
</MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeViewItem>
</TreeViewItem>
</TreeView>
Also change your code behind event handler as
private void ContextMenu_ContextMenuOpening_1(object sender, RoutedEventArgs e)
{
}

Categories