I'm trying to make a shared menu between something on my top menu bar of my app, and the right click context menu of something in my interface in WPF. I've googled aroudn but I can't figure out hwo to share ONLY the menuitems list.
Here is a picture of the UI to help describe it:
The way this works is when an item in the list (as shown in the background) is selected, this menu becomes available to use. I would like to make it so that when you right click an item in the list, it also shows the same menu. I would like to avoid duplicating code, so I defined a resource for MenuItem in my window resources:
<MenuItem x:Key="modUtilsMenu">
<MenuItem Header="{Binding SelectedMod.ModName}" IsEnabled="False" FontWeight="Bold" />
<MenuItem Header="{DynamicResource string_Checkforupdates}" Command="{Binding SelectedModCheckForUpdatesCommand}" ToolTip="{DynamicResource string_tooltip_checksForUpdatesToThisMod}" >
<MenuItem.Icon>
<fa:ImageAwesome Style="{StaticResource EnableDisableImageStyle}" Icon="Cloud" Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Height="16" Width="16"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="{DynamicResource string_RestoremodfromME3Tweaks}" Command="{Binding RestoreModFromME3TweaksCommand}" ToolTip="{DynamicResource string_tooltip_forcesUpdateCheck}" >
<MenuItem.Icon>
<fa:ImageAwesome Style="{StaticResource EnableDisableImageStyle}" Icon="CloudDownload" Foreground="{DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}}" Height="16" Width="16" RenderOptions.BitmapScalingMode="HighQuality"/>
</MenuItem.Icon>
</MenuItem>
...
I then add it to the interface as a sub element of the Mod Utils menuitem:
<MenuItem Header="{DynamicResource string_ModUtils}" Padding="4" IsEnabled="{Binding SelectedMod, Converter={StaticResource NullEnabledConverter}}">
<StaticResource ResourceKey="modUtilsMenu"/>
</MenuItem>
Obviously this doesn't work as it has a second MenuItem defined in the resource.
However, I am not sure how I can store a "list" of menu items to add as children of another object, as the root container element of MenuItem and ContextMenu are not the same. These are all command based menu items. I will have the same issue with a context menu too - how do I only share the contents and not the container? Do I have to do data binding?
I have looked at How do I share a menu definition between a context menu and a regular menu in WPF, but that seems to be just for single menu items. I suppose I could do it for every one of them, but I'm looking to see if there's a way to do this where I only have to update it in one place instead of three to make it work.
Menu and ContextMenu are both of type ItemsControl. You can treat them like this e.g. bind to a collection of item models and specify a DataTemplate.
The following example creates a collection of MenuItem as XAML resource.
To allow multiple instances of the collection it is important to to set the x:Shared attribute to False. Otherwise the menu will be rendered only in one location of the visual tree, no matter the number of references:
<Window>
<Window.Resources>
<x:Array x:Key="SharedMenuItems"
Type="MenuItem"
x:Shared="False">
<MenuItem Header="File">
<MenuItem Header="Save" />
</MenuItem>
<MenuItem Header="Settings" />
</x:Array>
</Window.Resources>
<StackPanel x:Name="RootPanel" viewModels:Item.IsMarkedAsRead="True">
<Menu ItemsSource="{StaticResource SharedMenuItems}" />
<Grid>
<Grid.ContextMenu>
<ContextMenu ItemsSource="{StaticResource SharedMenuItems}" />
</Grid.ContextMenu>
</Grid>
</StackPanel>
</Window>
Related
I try to search on internet but I not find anything. I want to show on the user when is click on the menu in menuitem what is the shortcut for this command (menuitem).
For example I want to make like "Build Solution" and is can see what shortcut is have.
Here is my xaml what I try:
<MenuItem Name="HelpMenuItem" HorizontalContentAlignment="Center" MouseLeave="HelpButtonMouseLeave" MouseEnter="HelpButtonMouseEnter" Header="{catel:LanguageBinding ResourceName=HelpSubMenu}" Command="{Binding Help}">
<MenuItem.InputBindings>
<KeyBinding Key="F1" Gesture="F1" Modifiers="Control" Command="Help" />
</MenuItem.InputBindings>
</MenuItem>
Is it possible to make it only with xaml
You can use InputGestureText property of the MenuItem. According to MSDN it designed exactly for this purporse (https://msdn.microsoft.com/ru-ru/library/system.windows.controls.menuitem.inputgesturetext%28v=vs.110%29.aspx).
<MenuItem Name="HelpMenuItem" Header="Help" InputGestureText="F1" />
Edit
Unfortunately it's not works for root MenuItems. For this case you can write something like this.
<MenuItem>
<MenuItem.Header>
<DockPanel>
<TextBlock Text="Help" Margin="0,0,10,0" />
<TextBlock Text="Ctrl+F1" />
</DockPanel>
</MenuItem.Header>
</MenuItem>
I'm trying to populate a menu item with a collection of children items. That was easy, however I need to add an extra that's always present that performs an "add" operation. I used a composite collection to add this on to the existing collection of items that need to be displayed.
Here's the code:
<MenuItem Header="Time Ranges" x:Name="TimeRangesMenuItem"
Background="{StaticResource TitleBarButtonBackgroundBrush}"
Margin="2">
<MenuItem.Resources>
<CollectionViewSource Source="{Binding ElementName=TimeRangesMenuItem, Path=DataContext.TimeSpans}" x:Key="TimeSpanMenuItems" />
</MenuItem.Resources>
<MenuItem.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource TimeSpanMenuItems}}" />
<Separator />
<MenuItem Header="Add New" cal:Message.Attach="NewTimeSpan()" />
</CompositeCollection>
</MenuItem.ItemsSource>
<MenuItem.ItemTemplate>
<ItemContainerTemplate>
<MenuItem Header="{Binding Name}" cal:Message.Attach="ConfigureTimeSpan()" />
</ItemContainerTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
It works, almost. The DataContext.TimeSpans ViewModel's I'm trying to display are "nested" inside two MenuItems, rather than just populating one, so I get this strange behavior (this only has a single TimeSpanViewModel "Time Span":
Mouse outside the "inner" MenuItem. Note, the inner one is functional if you press it:
Normal MenuItem:
Anyone got any ideas on how to fix this?
What is an item ItemContainerTemplate...
I think you want to manipulate the MenuItem.ItemContainerStyle instead, otherwise you create two MenuItems as observed.
The MenuItem.ItemTemplate already defines what is inside the given item container (varies by control, here MenuItem, in a ComboBox it's a ComboBoxItem, etc.). As there does not appear to be an ItemContainerTemplate property on the MenuItem you might only be able to use it that way implementing a selector that returns your template and setting it as ItemContainerTemplateSelector.
I have a ContextMenu with a MenuItem inside it. The MenuItem is a TextBlock as shown in the below code:
<ContextMenu>
<Border>
<MenuItem>
<MenuItem.Header>
<TextBlock Text="ACK" HorizontalAlignment="Right"/>
</MenuItem.Header>
</MenuItem>
</Border>
</ContextMenu>
How do I enable or disable it at runtime. If I click it once, it should be disabled.
PS: I don't want to write code-behind for this. I need to achieve it from the XAML as this is done in a UserControl and is going to be used in many applications.
I am creating a toolbar usercontrol which includes some dynamically added menuitems. The menuitems are part of observable collections of controls in the data context of the usercontrol, and are bound to the items source of their "top level" menu items as shown in the code below.
<UserControl.Resources>
<ResourceDictionary>
<MenuItem x:Key="fileKey" x:Shared="False" Header="_File" ItemsSource="{Binding FileMenuItems}" />
<MenuItem x:Key="viewKey" x:Shared="False" Header="_View" ItemsSource="{Binding ViewMenuItems}" />
...
Some of these top level menuitems are duplicated in multiple parts of the view in a primary dropdown menu as well as a main text menu bar.
<Menu Name="dropDownMenu">
<MenuItem>
<StaticResource ResourceKey="fileKey" />
<StaticResource ResourceKey="viewKey" />
</MenuItem>
</Menu>
...
<StackPanel x:Name="TextMenuPanel" Orientation="Horizontal">
<Menu Name="File">
<StaticResource ResourceKey="fileKey" />
</Menu>
</StackPanel>
The issue I am having is that if I open, say "File", from one menu, then the other menu, then attempt to open the first menu again it shows an empty box with no headers etc. of the original size of the menu, while the previously opened menu continues to display correctly if reopened.
How can I correctly show the bound menuitems in more than one place without breaking the view?
My problem is twofold, but i guess that they are related, and if I manage to fix one of them, I will solve both.
First of, lets see the xaml code for a ContextMenu that is linked to a Caliburn.Micro view model:
<ContextMenu>
<MenuItem Header="Configure modem" ItemsSource="{Binding Modems}">
<MenuItem.ItemTemplate>
<DataTemplate>
<MenuItem>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ca:ActionMessage MethodName="SelectModem">
<ca:Parameter Value="{Binding Path=DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />
</ca:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
<MenuItem.Header>
<DockPanel>
<Image DockPanel.Dock="Left" Source="{Binding CarrierProfile.CarrierProfileIcon}" Width="40" Height="40"/>
<TextBlock Text="{Binding MenuText}" VerticalAlignment="Center" Margin="10 0"/>
</DockPanel>
</MenuItem.Header>
</MenuItem>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
</ContextMenu>
So basically this is just a DataTemplate where I set the Header to a DockPanel containing an image and a TextBlock.
One MenuItem looks like this:
Here you can see the main problem. You can see that there are "two selections". One outer selection, and one inner. If I click the inner selection, everything is fine, and my SelectModem method is called from my view model. However, if you click the outer selection the context menu goes away so that user thinks he has made a selection, but actually no method is called on the view model.
My second problem is that if I disable the MenuItem by adding IsEnabled="False" in the code above, the menu item looks disabled (text is grayed out), I cannot make the inner selection, but on hover is still shows the outer selection, and when clicked the menu goes away (but nothing is triggered in my view model)
So the question is: How can I get rid of the the outer selection?