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>
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 to set two color background to a custom tree view (wpf). You can set this propriety in a DataGrid. I could not figure out a way to do it for a tree view.
I also want to set the selection of a element to be as big as the cell.
<TreeView Grid.Row="2" Name="TreeView" DataContext="{Binding Path=TreeModel}" ItemsSource="{Binding TreeItems}" SelectedItemChanged="TreeView_OnSelectedItemChanged">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:NodeViewModel}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding NameNode}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Add" Command="{Binding AddMachinePart_Command}"/>
<MenuItem Header="Remove" Command="{Binding RemoveMachinePart_Command}" IsEnabled="{Binding IsModule}"/>
<MenuItem Header="Edit" Command="{Binding EditMachinePart_Command}" IsEnabled="{Binding IsModule}"/>
<Separator></Separator>
<MenuItem Header="Copy path" Command="{Binding CopyPath_Command}" IsEnabled="{Binding IsModule}"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Edit:
When using the solution from
https://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationindex(v=vs.110).aspx suggested #jschroedl
It would be ideal to be as large as the tree view grid like shown in picture below:
You will probably want to use ItemsControl.AlternationIndex in a Style to control how many colors to cycle (2 in your case).
MSDN Docs for ItemsControl.AlternationIndex has an example with ListBox which you can probably adapt to TreeView as well.
I want to have in my application a context menu "DefaultPrinter" which has some binded childs (another MenuItems) representing printer's names. Each child has a property IsCheckable set to true.
<MenuItem Header="DefaultPrinter" ItemsSource="{Binding AllPrinters}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="IsCheckable" Value="True"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
However, of course I want allow only one printer to be checked (this code doesn't suport that). I looked for solution in the Internet, but didn't find anything helpful.
The problem is that MenuItem derieves from ItemsControl and since that it has no concept of items selection (like Selector). I can try to write my own selection, but first, I would like to know is there better and simplier solution for achieving that goal.
Any help will be appreciated.
Could abuse a hidden RadioButton:
<MenuItem.ItemTemplate>
<DataTemplate>
<Grid>
<RadioButton GroupName="Printers"
IsChecked="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=MenuItem}}"
Visibility="Collapsed"/>
<TextBlock Text="{Binding FullName}"/>
</Grid>
</DataTemplate>
</MenuItem.ItemTemplate>
I'm having a weird problem with a simple ContextMenu using MahApps.Metro without any additional styling. When moving the cursor on top of the text or slightly around it, there is no problem. But when moving it further away, still inside the ContextMenu bounds, the Cursor is no longer on top of the MenuItem. Clicking now also doesn't result in any action at all besides closing the ContextMenu.
<ContextMenu ItemsSource="{Binding ContextItems}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" Command="{Binding Command}"/>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
What am I doing wrong? Why doesn't the MenuItem use the available space?
If your ContextItems holds a collection with viewmodels then I think this could help you (not tested):
<ContextMenu ItemsSource="{Binding ContextItems}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Text}" />
<Setter Property="Command" Value="{Binding Command}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
Command and Text should be the properties on the viewmodel object.
I havent used MahApps.Metro . Though you can override the template like this
<ContextMenu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" Command="{Binding Command}"/>
<MenuItem.Template>
<ControlTemplate>
<ContentPresenter Content="{Binding Header,RelativeSource={RelativeSource TemplatedParent}}">
</ContentPresenter>
</ControlTemplate>
</MenuItem.Template>
</MenuItem>
</DataTemplate>
</ContextMenu.ItemTemplate>
I hope this will help.
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...