I'm trying to do exactly what is described here, except with a Rectangle instead of a Button. I did what is described in the answer (among many other things), and I cannot get it to display as shown relative to the rectangle (which, in my case is being used by a button).
I am using a rectangle as a button because I didn't like the mouseover effects of a button and it seemed easier to just use a rectangle rather than building a custom button. As a note, I had this same problem even when I was using a button, in Expression Blend 4.
This is the XAML for my rectangle:
<Rectangle x:Name="rectangle" HorizontalAlignment="Left" MouseDown="MenuClicked" Height="55" VerticalAlignment="Top" Width="135" Grid.ColumnSpan="2" Margin="0,1,0,0" ContextMenuService.Placement="Bottom">
<Rectangle.ContextMenu>
<ContextMenu x:Name="Menu" >
<MenuItem x:Name="LoadXML" Header="Load XML" Command="{Binding Command}" CommandParameter="BrowseXML"/>
<MenuItem x:Name="SaveXML" Header="Save XML" Command="{Binding Command}" CommandParameter="SaveXML"/>
<MenuItem x:Name="SaveBinary" Header="Save Binary" Command="{Binding Command}" CommandParameter="SaveBinary"/>
<MenuItem x:Name="SaveText" Header="Save Text" Command="{Binding Command}" CommandParameter="SaveText"/>
</ContextMenu>
</Rectangle.ContextMenu>
<Rectangle.Fill>
<ImageBrush ImageSource="Resources/Logo.png" Stretch="Uniform" />
</Rectangle.Fill>
</Rectangle>
This still displays the contextmenu directly next to the point of mouse click. If I set Placement to bottom within the Context Menu code, rather than adding the ContextMenuService bit to the Rectangle, it displays it at the bottom or top relative to the entire window.
Any help would be appreciated. Thanks!
EDIT: I am also using a method to enable left-clicking of the rectangle. On MouseDown, it calls this method:
private void MenuClicked(object sender, System.Windows.RoutedEventArgs e)
{
Menu.PlacementTarget = this;
Menu.IsOpen = true;
}
You need to set the ContextMenuService.PlacementTarget property so the framework knows which element the context menu should be positioned relative to, e.g.:
<Rectangle x:Name="rectangle" ContextMenuService.PlacementTarget="{Binding RelativeSource={RelativeSource Self}}" ... />
Just add that property to your Rectangle declaration. When combined with ContextMenuService.Placement="Bottom", the context menu will appear at the bottom as you intended.
EDIT: Since you are opening the menu programatically, you need to set the Placement and PlacementTarget properties directly on the menu itself. The attached properties from ContextMenuService, when set on the menu's owner, will only take effect if the context menu is opened by conventional means, e.g., a right click. In your MouseDown handler, you are setting PlacementTarget = this;, but you should be setting PlacementTarget = rectangle;.
Related
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>
I have a simple window with a menu containing items bound to view models.
<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding ViewModels}">
<Menu.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding HeaderName}" Visibility="{Binding MenuVisibility}"
Command="{Binding DataContext.ChangeViewCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"/>
</DataTemplate>
</Menu.ItemTemplate>
</Menu>
<Viewbox Stretch="Fill">
<ContentControl Content="{Binding CurrentViewModel}"/>
</Viewbox>
</DockPanel>
Everything for the Menu's style is default plane jane. Nothing fancy. No modifications.
I'm noticing some odd hover behavior when testing the UI. If I mouse over one of the menu items and it becomes highlighted, it seems to 'trap' focus on that item even if the mouse leaves.
So lets says I'm mousing UP through my application, my mouse cursor passes over the menu, highlighting an item. My mouse never stops and attempts to click the Window bar to move the UI to another monitor, the click never lands on the menu bar. I have to click twice, once to remove focus from the menu item, and again to select and drag the window. This also prevents clicks on the minimize, maximize and close buttons as well, or any focus back inside the form. It seems that the MenuItem does not properly notice the mouse has left.
Any ideas? I've tried gutting the Menu and MenuItem styles and have had no success. I've changed the DataTemplate to contain a Grid and used Interactions to trigger the commands, but its ugly and seems hacky.
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'm implementing a .NET 4.5 WPF application on a touchscreen desktop. When testing my application, I realised that the tooltips for my buttons will not appear when I tap and hold the same button twice consecutively.
1) I tap and hold on Button A once, the tooltip for Button A appears as expected.
2) I tap and hold on Button A again (after the initial tooltip has disappeared), the tooltip will not appear again.
3) I tap and hold on Button B, tooltip for Button B appears.
4) I tap and hold on Button A now, tooltip for Button A now able to appear.
I am not sure whether this is the default behavior or it's something I did somewhere in my code that caused this to happen. Is there anything I can do to ensure the tooltip appears everytime?
Thanks for the help.
</StackPanel.Resources>
<ContentControl HorizontalAlignment="Center" VerticalAlignment="Center" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<MvvmLight:EventToCommand Command="{Binding MessageInfoVm.ShowInfoMessageCommand}" CommandParameter="{Binding ToolTipOk}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Button ToolTipService.ShowOnDisabled="True" ToolTip="{Binding ToolTipOk}" Command="{Binding OkCommand}" />
</ContentControl>
Try ToolTipService.ShowOnDisabled="True"
or additional event for MouseLeftButtonDown
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?