Contextmenu - disable right click to open it - c#

I have such xaml code:
<Grid x:Name="boardGrid">
<Grid.ContextMenu>
<ContextMenu Opacity="0.7" x:Name="menuContext">
</ContextMenu>
</Grid.ContextMenu>
</Grid>
I generate grid's items in code behind. What I want is to disable context menu opening on right click. I want to open it when certains conditions occur.
This is what I have in .cs file:
generating Unit's objects and putting them into Grid;
each object has unit.MouseRightButtonUp += unit_MouseRightButton
void unit_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
if (CurrentGame.CurrentPlayer.HasTurn == false) return;
.....
ContextMenu.IsOpen = true;
}
So it means that Contextmenu should be open only if condition is fulfilled but it opens anyway.

You can set the attached property ContextMenuService.IsEnabled to false. Then you can manually popup the ContextMenu.
You must set that property for the GUI element that owns the menu. Setting it for the menu itself will do nothing.
<Grid x:Name="boardGrid" ContextMenuService.IsEnabled="false">
<!-- ... -->
</Grid>
void unit_MouseRightButtonUp(object sender, MouseButtonEventArgs e) {
if (CurrentGame.CurrentPlayer.HasTurn == false) return;
.....
boardGrid.ContextMenu.IsOpen = true;
}

Related

How to enable menuitems on a ContextMenu - WPF

I'm trying to create a ContextMenu on a UserControl derived object. Note: This is NOT a WinForms App, it is pure WPF.
So I create the ContextMenu thus:
<UserControl.Resources>
<ContextMenu x:Key="cmLCD_CopyCutPaste">
<MenuItem Name="CutOption" Header="{x:Static p:Resources.Popup_Cut}" Command="Cut" Click="MenuItem_Cut" IsEnabled="True"/>
<MenuItem Name="CopyOption" Header="{x:Static p:Resources.Popup_Copy}" Command="Copy" Click="MenuItem_Copy" IsEnabled="True"/>
<MenuItem Name="PasteOption" Header="{x:Static p:Resources.Popup_Paste}" Command="Paste" Click="MenuItem_Paste" IsEnabled="True"/>
</ContextMenu>
</UserControl.Resources>
The mousebutton event is setup thus:
d:DesignHeight="66" d:DesignWidth="340" Focusable="True" KeyDown="Grid_KeyDown" MouseRightButtonDown="EMS_UI_LCDscreen_MouseRightButtonDown" >
In the code behind, the constructor starts like this:
public EMS_UI_LCDscreen()
{
InitializeComponent();
// Find the ContextMenu created on this object - it is called cmLCD_CopyCutPaste
ContextMenu cm = FindResource("cmLCD_CopyCutPaste") as ContextMenu;
// If we found the contextMenu, assign it the ContextMenu placeholder for this instance.
if (cm != null)
{
ContextMenu = cm;
}
...
The mouse click(right button) is handled like this:
private void EMS_UI_LCDscreen_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
if (this.ContextMenu is ContextMenu cm)
{
if (cm != null)
{
if (DataContext is DeviceEditorData ded)
{
cm.DataContext = ded.Device.GetStructuredLocation(0);
cm.IsEnabled = true;
cm.PlacementTarget = sender as Button;
cm.IsOpen = true;
}
}
}
}
There are the three event handlers to actually respond to the user selection on the ContextMenu:
private void MenuItem_Cut(object sender, RoutedEventArgs e)
{
}
private void MenuItem_Copy(object sender, RoutedEventArgs e)
{
}
private void MenuItem_Paste(object sender, RoutedEventArgs e)
{
}
View of the ContextMenu being shown on the LCD Image component
The component I have created appears in a few different contexts, but the one I'm mainly interested in is inside of a DataGrid that shows various items of data, each with one of these components. when right clicked, the component faithfully displays the popup context menu as expected..... BUT all the items on the menu are grayed out and basically not enabled.
So my question is, what is the missing piece of glue that effectively enables the menu items so that they can be clicked to do the required actions. Most of the answers already seen on the net go into detail of how to do it in a WinForms app, but despite hours of searching, I can find no clear solution to what should be a very simple task of enabling the menu items.
Can some kind soul please put me out of my anguish and in a few lines of code show me how to do it! Thank you
UPDATE: This is the XAML implementation for the LCD Component:
<UserControl x:Class="EMS_Config_Tool.UIComponents.WPF.EMS_UI_LCDscreen"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:p="clr-namespace:EMS_Config_Tool.Properties"
mc:Ignorable="d"
d:DesignHeight="66" d:DesignWidth="340" Focusable="True" KeyDown="Grid_KeyDown" MouseRightButtonDown="EMS_UI_LCDscreen_MouseRightButtonDown" >
<UserControl.Resources>
<ContextMenu x:Key="cmLCD_CopyCutPaste">
<MenuItem Name="CutOption" Header="{x:Static p:Resources.Popup_Cut}" Command="{Binding Cut}"/>
<MenuItem Name="CopyOption" Header="{x:Static p:Resources.Popup_Copy}" Command="{Binding Copy}"/>
<MenuItem Name="PasteOption" Header="{x:Static p:Resources.Popup_Paste}" Command="{Binding Paste}"/>
</ContextMenu>
</UserControl.Resources>
<UserControl.CommandBindings>
<CommandBinding Command="Cut"
CanExecute="CutCommand_CanExecute"
Executed="CutCommand_Executed" />
<CommandBinding Command="Copy"
CanExecute="CopyCommand_CanExecute"
Executed="CopyCommand_Executed" />
<CommandBinding Command="Paste"
CanExecute="PasteCommand_CanExecute"
Executed="PasteCommand_Executed" />
</UserControl.CommandBindings>
</UserControl>
As can be seen, it is very simple - there are no items added to the control - it only serves as a Canvas upon which the code behind draws all the needed items which are purely graphic "draw" items.
This is the implementations of the 6 methods referenced, in the corresponding .cs file for the xaml above:
private void CutCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
// Verify relevant conditions and set CanExecuteRoutedEventArgs.CanExecute accordingly
e.CanExecute = true;
}
private void CutCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Execute the command action
if (sender is EMS_UI_LCDscreen lcd)
{
if (TheDevice != null)
{
Clipboard.SetDataObject(TheDevice.GetStructuredLocation(0).ToString());
TheDevice.SetLocation(0, "");
lcd.StructuredTextToShow = TheDevice.GetStructuredLocation(0);
}
else
{
Clipboard.SetDataObject(lcd.StructuredTextToShow.ToString());
lcd.StructuredTextToShow.SetString("");
}
}
}
private void CopyCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
// Verify relevant conditions and set CanExecuteRoutedEventArgs.CanExecute accordingly
e.CanExecute = true;
}
private void CopyCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Execute the command action
if (sender is EMS_UI_LCDscreen lcd)
{
if (TheDevice!=null)
Clipboard.SetDataObject(TheDevice.GetStructuredLocation(0).ToString());
else
Clipboard.SetDataObject(lcd.StructuredTextToShow.ToString());
}
}
private void PasteCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
// Verify relevant conditions and set CanExecuteRoutedEventArgs.CanExecute accordingly
IDataObject iData = Clipboard.GetDataObject();
// Is the Data Text?
if (iData.GetDataPresent(DataFormats.Text))
e.CanExecute = true;
else
e.CanExecute = false;
}
private void PasteCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Execute the command action
if (sender is EMS_UI_LCDscreen lcd)
{
// Retrieves data
IDataObject iData = Clipboard.GetDataObject();
// Is the Data Text?
if (iData.GetDataPresent(DataFormats.Text))
{
if (TheDevice != null)
{
TheDevice.SetLocation(0, (string)iData.GetData(DataFormats.Text));
lcd.StructuredTextToShow = TheDevice.GetStructuredLocation(0);
}
else
{
lcd.StructuredTextToShow.SetString((string)iData.GetData(DataFormats.Text));
}
}
}
}
Finally, the ContextMenu is assigned to the object in the constructor:
public EMS_UI_LCDscreen()
{
InitializeComponent();
// Find the ContextMenu created on this object - it is called cmLCD_CopyCutPaste
ContextMenu cm = FindResource("cmLCD_CopyCutPaste") as ContextMenu;
// If we found the contextMenu, assign it the ContextMenu placeholder for this instance.
if (cm != null)
{
ContextMenu = cm;
}
...
The menu is shown on the component in response to right-click, the cut/copy/paste methods respond to the key ops, but clicking on the menu items does not fire the corresponding methods.
I can't see why that should be so, it all looks correct to me, but perhaps there is something missing that is preventing it working. One suggestion was to use a "relay command" type of thingy, but what and how that may be, is unclear.
You should remove all code that sets IsEnabled to true. It's redundant as the value is true by default.
The buttons are disabled because you have (accidentally?) attached a command to the MenuItem.Command property but no corresponding command handler.
The framework will try to invoke a CanExecute handler. Since there is no one defined, a default handler is returned that sets CanExecuteRoutedEventArgs.CanExecute to false, which will disable the button (ICommandSource).
Not sure if your intention was to use a command here or you wrongfully guessed the Command property is like a name property (since you have also registered Click event handlers). See Commanding Overview to learn more.
Anyway, this is how you can register a command handler:
You have assigned predefined application commands (cut, copy and paste - the MenuItem.Command string values in your XAML implicitly references the static ApplicationCommands commands). These commands are routed commands (behavior is identical to routed events - in fact routed commands are routed events). Therefore, you must define the command bindings on a parent element of the command source (the element that invokes the command) as the command will bubble up the tree.
A UIElement.CommandBinding consists of the specified CommandBinding.Executed handler and the optional CommandBinding.CanExecute handler.
Use the CanExecute handler to control the disabled states of the command source e.g., a Button. If the command source should be always enabled, simply omit the CanExecute handler.
XAML
<Window>
<Window.CommandBindings>
<CommandBinding Command="Cut"
CanExecute="CutCommand_CanExecute"
Executed="CutCommand_Executed" />
</Window.CommandBindings>
</Window>
C#
partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var cutCommandBinding =
new CommandBinding(ApplicationCommands.Cut, CutCommand_Executed, CutCommand_CanExecute)
this.CommandBindings.Add(cutCommandBinding);
}
}
Then create the corresponding command handlers in the code-behind.
private void CutCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
// Verify relevant conditions and set CanExecuteRoutedEventArgs.CanExecute accordingly
e.CanExecute = true;
}
private void CutCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
// Execute the command action
}
Update
To force command handling on the UserControl, you can explicitly set the MenuItem.CommandTarget property to reference the UserControl.
You can also assign the UserControl.Contextmenu from XAML:
<UserControl>
<UserControl.Resources>
<Style TargetType="MenuItem">
<Setter Property="CommandTarget"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget}" />
</Style>
</UserControl.Resources>
<UserControl.Contextmenu>
<ContextMenu>
<MenuItem Name="CutOption" Header="{x:Static p:Resources.Popup_Cut}" Command="{Binding Cut}"/>
<MenuItem Name="CopyOption" Header="{x:Static p:Resources.Popup_Copy}" Command="{Binding Copy}"/>
<MenuItem Name="PasteOption" Header="{x:Static p:Resources.Popup_Paste}" Command="{Binding Paste}"/>
</ContextMenu>
</UserControl.Contextmenu>
<UserControl.CommandBindings>
<CommandBinding Command="Cut"
CanExecute="CutCommand_CanExecute"
Executed="CutCommand_Executed" />
<CommandBinding Command="Copy"
CanExecute="CopyCommand_CanExecute"
Executed="CopyCommand_Executed" />
<CommandBinding Command="Paste"
CanExecute="PasteCommand_CanExecute"
Executed="PasteCommand_Executed" />
</UserControl.CommandBindings>
</UserControl>
This was the solution that finally worked for me. The elixir was assigning the commands, not with the "Binding" term, but directly:
<UserControl x:Class="EMS_Config_Tool.UIComponents.WPF.EMS_UI_LCDscreen"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:p="clr-namespace:EMS_Config_Tool.Properties"
mc:Ignorable="d"
d:DesignHeight="66" d:DesignWidth="340" Focusable="True" KeyDown="Grid_KeyDown" MouseRightButtonDown="EMS_UI_LCDscreen_MouseRightButtonDown" >
<UserControl.Resources>
<Style TargetType="MenuItem">
<Setter Property="CommandTarget"
Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}, Path=PlacementTarget}" />
</Style>
</UserControl.Resources>
<UserControl.ContextMenu>
<ContextMenu>
<MenuItem Name="CutOption" Header="{x:Static p:Resources.Popup_Cut}" Command="Cut" />
<MenuItem Name="CopyOption" Header="{x:Static p:Resources.Popup_Copy}" Command="Copy" />
<MenuItem Name="PasteOption" Header="{x:Static p:Resources.Popup_Paste}" Command="Paste" />
</ContextMenu>
</UserControl.ContextMenu>
<UserControl.CommandBindings>
<CommandBinding Command="Cut"
CanExecute="CutCommand_CanExecute"
Executed="CutCommand_Executed" />
<CommandBinding Command="Copy"
CanExecute="CopyCommand_CanExecute"
Executed="CopyCommand_Executed" />
<CommandBinding Command="Paste"
CanExecute="PasteCommand_CanExecute"
Executed="PasteCommand_Executed" />
</UserControl.CommandBindings>
</UserControl>
The constructor and assignment of images looks like this:
public EMS_UI_LCDscreen()
{
InitializeComponent();
Image ObjImage1 = new Image();
Image ObjImage2 = new Image();
Image ObjImage3 = new Image();
ObjImage1.Source = new BitmapImage(new Uri(#"pack://application:,,,/Graphics\Misc Icons\Cut.png"));
CutOption.Icon = ObjImage1;
ObjImage2.Source = new BitmapImage(new Uri(#"pack://application:,,,/Graphics\Misc Icons\Copy.png"));
CopyOption.Icon = ObjImage2;
ObjImage3.Source = new BitmapImage(new Uri(#"pack://application:,,,/Graphics\Misc Icons\Paste.png"));
PasteOption.Icon = ObjImage3;
...
... and displaying the context menu on the component in response to the mouse right click:
private void EMS_UI_LCDscreen_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
if (ContextMenu is ContextMenu cm)
{
if (DataContext is DeviceEditorData ded)
{
cm.DataContext = ded.Device.GetStructuredLocation((uint)LocationIndex);
cm.IsEnabled = true;
cm.PlacementTarget = sender as EMS_UI_LCDscreen;
cm.IsOpen = true;
}
if (DataContext is EMSBasicDevice dev)
{
cm.DataContext = dev.GetStructuredLocation((uint)LocationIndex);
cm.IsEnabled = true;
cm.PlacementTarget = sender as EMS_UI_LCDscreen;
cm.IsOpen = true;
}
}
}
For brevity, I have not shown the ..._CanExecute / ...Executed methods, they are as shown previously in the question.
Thanks to all who have helped in resolving this issue.
View of the finished context Menu in situ
So, if you are using DataContext and Binding's, you can do the following
remove the direct control with event handlers, i.e. Click, and direct setting of Enabled.
use Binding to bind menu action to the handler inside the view model: Command={Binding CutCommand} (or any other handler).
use ICommand.CanExecute of the command handler (CutCommand in the sample above). to manage Enabled state of menu item.
So, let's put all together.
In the XAML
<MenuItem Name="CutOption" Header="{x:Static p:Resources.Popup_Cut}"
Command="{Binding CutCommand}"/>
In the ViewModel
class ViewModel: INotifyPropertyChanged
{
...
public ICommand CutCommand { get; }
public ViewModel()
{
//you can just omit second arg if you always can call Cut.
CutCommand = new RelayCommand(CutHandler, ()=>CanCut()));
}
...
}
Here RelayCommand is a https://learn.microsoft.com/en-us/windows/communitytoolkit/mvvm/relaycommand or any other implementation of simple command.
If you need to update the Enabled state on-the-fly, you can call CommandManager.InvalidateRequerySuggested(); to reevaluate CanExecute of all commands.

XAML WPF CheckBox Validation

I have a list of CheckBox'es. I would like the user to select at least one before click the next button.
I would want the Button to remain Enabled, but use a TextBlock below the CheckBox to show the prompt to select at least one CheckBox.
How can I check that.
Code:
XAML
<CheckBox x:Name="CheckBox1" Content="CheckBox1" />
<CheckBox x:Name="CheckBox2" Content="CheckBox2" />
<CheckBox x:Name="CheckBox3" Content="CheckBox3" />
<CheckBox x:Name="CheckBox4" Content="CheckBox4" />
<Button x:Name="NextButton" Click="NextButton_Click"/>
Code Behind
private void NextButton_Click(object sender, RoutedEventArgs e) {
if (CheckBox1.IsChecked ?? false) {
// do something
}
// same for other checkBoxes
}
private void NextButton_Click(object sender, RoutedEventArgs e)
{
if (!CheckBox1.IsChecked && !CheckBox2.IsChecked && !CheckBox3.IsChecked && !CheckBox4.IsChecked)
{
// update TextBlock to alert the user
}
else
{
if (CheckBox1.IsChecked)
{
// do something
}
// same for other checkboxes
}
}
You can also do the following, based on the example of just one CheckBox:
XAML
<CheckBox x:Name="CheckBox1" Content="CheckBox1" Checked="CheckBox1_OnChecked"/>
// after all your CheckBoxes insert TextBlock below
// which is Visible by default (but invisible once any CheckBox is checked)
<TextBlock x:Name="TextBlock" Visibility="Visible" Text="Please, select at least 1 checkbox"/>
<Button x:Name="NextButton" Click="NextButton_Click" Height="Auto" Width="Auto" Content="Button"/>
Code Behind
private void NextButton_Click(object sender, RoutedEventArgs e)
{
// your code
}
// We make Visibility of TextBox hidden
// Think for yourself how to take into account
// several CheckBoxes checked vs unchecked
private void CheckBox1_OnChecked(object sender, RoutedEventArgs e)
{
TextBlock.Visibility = Visibility.Hidden;
}
Think for yourself how to take into account several CheckBoxes checked vs unchecked, you may also use CheckBoxes event handler for Unchecked event: Unchecked="CheckBox1_OnUnchecked"

Flyout causing the app to crash [Windows 10] C# XAML

I want the program to show the attached Flyout when user Holding the control (on the mobile) or when the user Right-click the control (on PC).
Here is my XAML :
<DataTemplate x:DataType="data:Cards" x:Key="card">
<StackPanel x:Name="cardstack" Holding="cardstack_Holding" KeyDown="cardstack_KeyDown" >
<StackPanel Background="Blue" Height="100" />
<FlyoutBase.AttachedFlyout>
<MenuFlyout x:Name="optionpass">
<MenuFlyoutItem x:Name="delete" Text="Delete" Click="delete_Click"/>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
</StackPanel>
</DataTemplate>
and this is my C# :
private void cardstack_Holding(object sender, HoldingRoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
}
private void cardstack_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.RightButton)
{
FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
}
}
When I tap and Hold the Stackpanel on the mobile simulator, the Holding event works, but when I Right-click on my PC, it crashes! It says that "There are no attached Flyout!". I do not know what is wrong.
"Have you tried RightTapped event? Is it working?"
Yes and No :(
I just found out the solution to solve my problem.
Turns out you have to name the MenuFlyout like my one is x:Name = "option_menu", and the Flyoutbase.AttachedFlyout cannot be in the DataTemplate, means you have to put it anywhere else except in the DataTemplate, so that the .cs file can find the name of the MenuFlyout.
Here is my C# :
public void cardstack_Holding(object sender, HoldingRoutedEventArgs e)
{
option_menu.ShowAt(sender as FrameworkElement);
e.Handled = true;
}
private void cardstack_PointerPressed(object sender, PointerRoutedEventArgs e)
{
Pointer pointr = e.Pointer;
if (pointr.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
{
Windows.UI.Input.PointerPoint pointrd = e.GetCurrentPoint(sender as UIElement);
if (pointrd.Properties.IsRightButtonPressed)
{
option_menu.ShowAt(sender as FrameworkElement);
}
}
e.Handled = true;
}
Notice that before this I use ShowAttachedFlyout, now I use option_menu.ShowAt.
KeyDown event somehow did not work with my app, so I used PointerPressed instead.
Hope this helps. (0w0)/

How to create a ContextMenu when the mouse button is pressed

I made a code for a DataGrid that fire the right mouse button event, in particular:
private void Squadre_DataGrid_MouseClick(object sender, MouseEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed)
{
//Context menu
}
}
I want create a ContextMenu inside the condition, and associate for each item of the ContextMenu a method that will be executed if the item will be choose.
How to do this?
Perhaps you can achieve that in XAML. Assuming you want to have a context menu for the rows of your DataGrid, you can add the ContextMenu property to your DataGridRow, for example:
<DataGrid>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="ContextMenu" Value="{StaticResource theContextMenu}" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
Then add the context menu itself in the resource dictionary:
<Window.Resources>
<ResourceDictionary>
<ContextMenu x:Key="theContextMenu">
<MenuItem Header="Menu Item 1" Click="menuItem1_Click">
</MenuItem>
<MenuItem Header="Menu Item 2" Click="menuItem2_Click">
</MenuItem>
</ContextMenu>
</ResourceDictionary>
</Window.Resources>
Then write a click event handler for each menu item to execute your method:
private void menuItem1_Click(object sender, RoutedEventArgs e)
{
// execute your method..
}
private void menuItem2_Click(object sender, RoutedEventArgs e)
{
// execute your method..
}
You could bind datacontext content to a propertie and than fill It (propertie) in your Button event. Don't forget to set Update condition in Contextmenu binding (xaml)
In my view the best form of work this out is adding an ContextMenu for each row of DataGrid, we can do it in the following way:
In the XAML, place in your DataGrid an listener to event LoadingRow:
<!-- resume version of declaration your DataGrid -->
<DataGrid x:Name="Squadre_DataGrid" LoadingRow="Squadre_DataGrid_LoadingRow" />
In the CodeBehind, come on add the ContextMenu for each row:
private void Squadre_DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
ContextMenu _contextMenu = new ContextMenu();
MenuItem mia = new MenuItem();//item 1
MenuItem mib = new MenuItem();//item 2
....
_contextMenu.Add(mia);
_contextMenu.Add(mib);
....
e.Row.ContextMenu = _contextMenu;//add context menu to row
}

ContextMenu disappears immediately after appearing

I have a context menu but it is disappearing instantly after it shows up.
<TextBlock Name="InputtedAddress" Text="{Binding Path=InputtedAddress}" MouseDown="InputtedAddress_MouseDown"/>
System.Windows.Controls.ContextMenu thisMenu;
private void InputtedAddress_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed)
{
thisMenu = new System.Windows.Controls.ContextMenu();
MenuItem thisMenuItem = new MenuItem() { Header = "Zoom to Incident" };
thisMenuItem.Click += new RoutedEventHandler(thisMenuItem_Click);
thisMenu.Items.Add(thisMenuItem);
thisMenu.IsOpen = true;
}
}
It's likely because you're not marking the MouseDown event to handled. Set e.Handled to true and it will no longer propagate and your ContextMenu will stay open.
That said, this is an awful way to assign a ContextMenu in the first place. Why not just do this:
<TextBlock ...>
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Zoom to Incident" Click="thisMenuItem_Click"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
You should assign your menu to the ContextMenu property of your TextBlock so that the opening and positioning will be taken care of for you. You also don't need to create the menu in each MouseDown; just create it once and assign it to the ContextMenu property.
In XAML:
<TextBlock
Name="InputtedAddress"
Text="{Binding Path=InputtedAddress}"
>
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem
Header="Zoom to Incident"
Click="ContextMenu_Click"
/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
If you do want to show it manually you will need to position it before showing it by setting the PlacementTarget property, something like this:
private void InputtedAddress_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed)
{
thisMenuPlacementTarget = InputtedAddress;
thisMenu.IsOpen = true;
}
}
P.S. "Inputted" is not a word :)

Categories

Resources