I wish to have two context menu in grid view in my WPf based desktop application .
Currently i am able to display one context menu, but I want to show context menu 1 on one condition and context menu 2 on another condition . How to do that?
I am usign following XAML code to show grid and context menu
<dg:UCGrid x:Name="grdLetVariables" Grid.Row="2" GridTypeSource="LetGrid"
DataContext="{Binding}" >
<dg:UCGrid.Resources>
<x:Array Type="{x:Type sys:Object}" x:Key="GridExtensions">
<MenuItem Header="Delete" Click="ContextMenuDelete">
<MenuItem.Icon>
<Image Height="10" Source="../images/Delete.png"/>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Move Up" Click="MoveUpLetGrdRow">
<MenuItem.Icon>
<Image Height="14" Source="../images/UpMove.png"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Move Down" Click="MoveDownLetGrdRow">
<MenuItem.Icon>
<Image Height="14" Source="../images/DownMove.png"/>
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Cancel" Click="CancelLetGrdRowEdit"/>
</x:Array>
</dg:UCGrid.Resources>
<dg:UCGrid.ContextMenu>
<ContextMenu>
<ContextMenu.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{StaticResource GridExtensions}" />
</CompositeCollection>
</ContextMenu.ItemsSource>
</ContextMenu>
</dg:UCGrid.ContextMenu>
</dg:UCGrid>
</Grid>
Triggers on DataGrid can help you here. Code below is just for illustration ...
<UserContorl.Resources>
<ContextMenu x:Key="Condition1ContextMenu" ../>
<ContextMenu x:Key="Condition2ContextMenu" ../>
</UserControl.Resources>
...
<Style TargetType="{x:Type dg:UCGrid}">
<Style.Triggers>
<DataTrigger Binding="{Binding Condition1}" Value="Value1">
<Setter Property="ContextMenu" Value="{StaticResource Condition1ContextMenu}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Condition2}" Value="Value2">
<Setter Property="ContextMenu" Value="{StaticResource Condition2ContextMenu}"/>
</DataTrigger>
</Style.Triggers>
</Style>
Ofcourse condition1 and condition2 must be exclusive of each other. If both of them are applicable on the data grid then due to order Condition2ContextMenu will take the precedence.
Let me know if this helps...
Related
I have the following XAML that produces a ListBox where each item contains another ListBox inside an Expander, and I have defined PageContextMenu as the context menu for the top level list and FrameContextMenu for the lower level list.
The problem: Both are displayed correctly, but click events are only working on the top level context menu and not the lower level context menu. For example, clicking on Delete Selected in PageContextMenu correctly invokes the associated handler, but clicking on Delete Selected Frame(s) in FrameContextMenu does NOT fire the associated handler. I'm not seeing any indication of an error, and even if I put a breakpoint in ContextDeleteFrames_Click it doesn't get hit. It's as if there's no handler associated with that menu entry at all.
I've looked at a number of other questions relating to context menus not working, but none seemed applicable. Is there some problem with the two list boxes being nested?
XAML:
<ListBox Name="PageListBox" ItemsSource="{Binding CurrentPack.Pages}" HorizontalAlignment="Stretch" SelectionMode="Extended">
<ListBox.Resources>
<ContextMenu x:Key="PageContextMenu">
<MenuItem Header="_Add" Name="ContextAddAddPage"/>
<MenuItem Header="_Edit" Name="ContextEditPage"/>
<MenuItem Header="_Delete Selected" Name="ContextDeletePage" Click="ContextDeletePage_Click"/>
</ContextMenu>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContextMenu" Value="{StaticResource PageContextMenu}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate >
<Border BorderThickness="2" BorderBrush="White" HorizontalAlignment="Stretch">
<StackPanel HorizontalAlignment="Stretch">
<Label Content="{Binding PresentationName}"/>
<Expander VerticalAlignment="Top" HorizontalAlignment="Stretch">
<Expander.Header>
<Label Content="{Binding FrameStatusText}"/>
</Expander.Header>
<ListBox Name="FrameListBox" ItemsSource="{Binding Frames}" HorizontalAlignment="Stretch" SelectionMode="Extended">
<ListBox.Resources>
<ContextMenu x:Key="FrameContextMenu">
<MenuItem Header="_Add Frame" Name="ContextAddFrame"/>
<MenuItem Header="_Edit Frame" Name="ContextEditFrame"/>
<MenuItem Header="_Delete Selected Frame(s)" Name="ContextDeleteFrames" Click="ContextDeleteFrames_Click"/>
<MenuItem Header="Show _Preview" Name="ContextShowPreview" Click="ContextShowPreview_Click"/>
</ContextMenu>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContextMenu" Value="{StaticResource FrameContextMenu}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding PresentationName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
Code Behind:
private void ContextDeletePage_Click(object sender, RoutedEventArgs e)
{ //this works
Workspace.Content.DeleteSelectedPages();
}
private void ContextDeleteFrames_Click(object sender, RoutedEventArgs e)
{ //this doesn't!
Workspace.Content.DeleteSelectedFrames();
}
Don't use events in a DataTemplate. They won't work.
Either move your second context menu from the DataTemplate's resources into the PageListBox resources like this:
<ListBox Name="PageListBox">
<ListBox.Resources>
<!-- ... other resources... -->
<ContextMenu x:Key="FrameContextMenu">
<MenuItem Header="_Add Frame" Name="ContextAddFrame"/>
<MenuItem Header="_Edit Frame" Name="ContextEditFrame"/>
<MenuItem Header="_Delete Selected Frame(s)" Click="ContextDeleteFrames_Click"/>
<MenuItem Header="Show _Preview" Name="ContextShowPreview" Click="ContextShowPreview_Click"/>
</ContextMenu>
</ListBox.Resources>
</ListBox>
...or use commands instead of events:
<MenuItem Header="_Delete Selected Frame(s)" Command="{Binding DeleteFrameCommand}"/>
where DeleteFrameCommand is a property of type ICommand or RoutedCommand.
If you want to use commands, you should be aware that a context menu is not in the visual tree of its PlacementTarget, so you'll have to use some helpers to make the bindings work (a binding proxy or PlacementTarget.Tag property etc.)
I want the user has the possibility to edit the header value.
The Header Value can be edited in a textbox when the property IsEditable is set to true.
Then I would like prevent the context menu closing when the header value is empty.
How can I achieve that ?
I tried to handle ContextMenuClosing event without success.
<MenuItem Header="{Binding Menu.Business}" Visibility="{Binding allowUI, Converter={StaticResource BoolToVisConverter} }" ContextMenuClosing="check" >
<MenuItem.Style>
<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}">
<Style.Triggers>
<DataTrigger Binding="{Binding Menu.IsEditable}" Value="True">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu Width="200">
<MenuItem>
<MenuItem.Header>
<TextBox Text="{Binding Menu.Business, UpdateSourceTrigger=PropertyChanged}" Width="150" Margin="0,0,-58,0"/>
</MenuItem.Header>
<MenuItem.Icon>
<Image Source="Images/closed_folder_grey_24.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
<MenuItem.Icon>
<Image Source="Images/closed_folder_grey_24.png" Margin="0" Height="26" Loaded="MenuItemImage_Loaded" />
</MenuItem.Icon>
</MenuItem>
private void check(object sender, ContextMenuEventArgs e)
{
if (String.IsNullOrEmpty(myViewModel.Menu.Business))
e.Handled = true;
}
Feel free to suggest an alternate approach to my problem if this isn't the best way to go about it.
I have a ToolBarTray and a TreeView. The tree has 2 items that are Concrete1 and Concrete2 classes respectively. I want the toolbar to have a different menu depending on which type of item is selected in the tree.
<ToolBarTray DockPanel.Dock="Top">
<ToolBar>
<ToolBar.Style>
<Style TargetType="{x:Type ToolBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tree, Path=SelectedItem, Converter={StaticResource convert}}" Value="{x:Type root:Concrete1}">
<!--what do i do here??-->
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tree, Path=SelectedItem, Converter={StaticResource convert}}" Value="{x:Type root:Concrete2}">
<!--what do i do here??-->
</DataTrigger>
</Style.Triggers>
</Style>
</ToolBar.Style>
<ToolBar.Resources>
<Menu x:Key="awd">
<MenuItem Header="AWD"></MenuItem>
</Menu>
<Menu x:Key="dwa">
<MenuItem Header="DWA"></MenuItem>
</Menu>
</ToolBar.Resources>
</ToolBar>
</ToolBarTray>
<TreeView x:Name="tree" ItemsSource="{Binding Families}"></TreeView>
I've gotten as far as being able to set any regular property (background, etc) of the toolbar depending on which item is selected. I don't know how to proceed to add specific Menus to the toolbar.
I think I've figured it out. I've only done this with a ContextMenu and outside of a style trigger but I imagine it would be the same principle.
<TreeView>
<TreeView.ContextMenu>
<ContextMenu>
<StaticResourceExtension ResourceKey="myMenuItem"></StaticResourceExtension>
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
I have a ListBox and within it multiple ListBoxItem objects. When the user right-clicks on a ListBoxItem a ContextMenu should appear with some MenuItem objects. The problem that I have is that when I put a Click event on the MenuItem objects I get a XamlParseException stating the following:
A first chance exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: 'Set connectionId threw an exception.' Line number '31' and line >position '34'.
I have to admit that I don't fully understand styles and resources and the other aspects of WPF. When I was designing this I just copied my code from the Internet. The code is as follows:
<ListBox Grid.Column="1" Grid.Row="1" MouseDoubleClick="MainListBox_MouseDoubleClick" Name="mainListBox" SelectionChanged="MainListBox_SelectionChanged">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Click="OpenMenuItem_Click" Header="Open"/>
<Separator/>
<MenuItem Header="Cut"/>
<MenuItem Header="Copy"/>
<Separator/>
<MenuItem Header="Delete"/>
<MenuItem Header="Rename"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
It works when I remove the Click event but of course the ContextMenu becomes useless.
Assign ContextMenu for ListBoxItem as given below.
<ListBox Grid.Column="1" Grid.Row="1" MouseDoubleClick="MainListBox_MouseDoubleClick" Name="mainListBox" SelectionChanged="MainListBox_SelectionChanged">
<ListBox.Resources>
<ContextMenu x:Key="CMenu">
<MenuItem Click="OpenMenuItem_Click" Header="Open"/>
<Separator/>
<MenuItem Header="Cut"/>
<MenuItem Header="Copy"/>
<Separator/>
<MenuItem Header="Delete"/>
<MenuItem Header="Rename"/>
</ContextMenu>
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContextMenu" Value="{StaticResource CMenu}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem Content="Test1"/>
</ListBox>
I want to develop a generic contextmenu in wpf with mvvm. I would like to display it in each viewModel that have a listview with the style: ItemContainerStyle="{DynamicResource ListViewItemContainerStyle}".
The context menu will have 2 options that will be enabled or not depending on some constraints in each view Model. The enabled or not will be managed by the canexecute of the command.
I have no problem if I put it in each view inside the listview, but I would like to have it only in one place other than in each listview. I have tried to put it in the ListViewItemContainerStyle but it shows an exception "it is not possible to add a System.Windows.Controls.ContextMenu to a System.Object". Here is my code snippet
<Style x:Key="ListViewItemContainerStyle"
TargetType="ListViewItem">
.
.
.
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Command="{Binding Path=Command}"
CommandParameter="AddNew">
<MenuItem.Header>
<TextBlock Text="{x:Static p:TextResources.New}" />
</MenuItem.Header>
</MenuItem>
<MenuItem Command="{Binding Path=Command}"
CommandParameter="Delete">
<MenuItem.Header>
<TextBlock Text="{x:Static p:TextResources.Delete}" />
</MenuItem.Header>
</MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
.
.
.
Any idea of how to do this?
Try this:
<ContextMenu x:Shared="False" x:Key="ListViewContextMenu>
<MenuItem Command="{Binding Path=Command}"
CommandParameter="AddNew">
<MenuItem.Header>
<TextBlock Text="{x:Static p:TextResources.New}" />
</MenuItem.Header>
</MenuItem>
<MenuItem Command="{Binding Path=Command}"
CommandParameter="Delete">
<MenuItem.Header>
<TextBlock Text="{x:Static p:TextResources.Delete}" />
</MenuItem.Header>
</MenuItem>
</ContextMenu>
<Style x:Key="ListViewItemContainerStyle"
TargetType="ListViewItem">
<Setter Property="ContextMenu" Value="{StaticResource ListViewContextMenu}"/>