Cannot set InputGestureText from code behind - c#

I am not able to set the InputGestureText from code behind.
The shortcut key works fine but the key-string is not displayed with the menu-item.
The XAML and C# code is mentioned below.
Environment:
VS2012 & .NET Framework 4.5
Any idea what I am missing?
//********************
//XAML
//********************
<DockPanel Grid.Row="0" Grid.ColumnSpan="2">
<Menu DockPanel.Dock="Top" Background="White">
<MenuItem x:Name="mnuFile" Header="_File">
<MenuItem x:Name="mnuFileNew" Header="_New..." />
<MenuItem x:Name="mnuFileOpen" Header="_Open for Editing..." />
<Separator />
<MenuItem x:Name="mnuFileExit" Header="E_xit" />
</MenuItem>
</Menu>
</DockPanel>
//********************
//********************
//Code Behind
//********************
public MainWindow()
{
InitializeComponent();
//File > New
mnuFileNew.Click += mnuFileNew_Click;
RoutedCommand cmdNewReport = new RoutedCommand();
cmdNewReport.InputGestures.Add(new KeyGesture(Key.N, ModifierKeys.Control | ModifierKeys.Shift, "Ctrl+Shift+N"));
CommandBindings.Add(new CommandBinding(cmdNewReport, mnuFileNew_Click));
}
void mnuFileNew_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("New Report not implemented!", this.Title, MessageBoxButton.OK, MessageBoxImage.Information);
}
//********************

If you want to use code behind, then try using this to display the shortcut:
mnuFileNew.Click += mnuFileNew_Click;
RoutedCommand cmdNewReport = new RoutedCommand();
var keyGesture = new KeyGesture(Key.N, ModifierKeys.Control | ModifierKeys.Shift, "Ctrl+Shift+N");
cmdNewReport.InputGestures.Add(keyGesture);
mnuFileNew.InputGestureText = keyGesture.DisplayString;
CommandBindings.Add(new CommandBinding(cmdNewReport, mnuFileNew_Click));

Related

Modifying image height from context menu in XAML

In my XAML page I define an image with a context menu:
<Image Height="{Binding Image.Height, Mode=TwoWay}" MaxHeight="2000" HorizontalAlignment="Left" StretchDirection="Both" Stretch="Uniform"
Source="{Binding Image.ImageData, Converter={StaticResource ImageByteConverter}}"
x:Name="Image1">
<Image.ContextMenu>
<ContextMenu>
<MenuItem Header="200" Click="ImageHeight200_Click" />
<MenuItem Header="400" Click="ImageHeight400_Click" />
<MenuItem Header="600" Click="ImageHeight600_Click" />
<MenuItem Header="800" Click="ImageHeight800_Click" />
<MenuItem Header="1000" Click="ImageHeight1000_Click" />
</ContextMenu>
</Image.ContextMenu>
</Image>
Now I want to add code to resize the image.
When I write something like this
private void ImageHeight200_Click(object sender, RoutedEventArgs e)
{
var img = (Image)e.Source;
img.Height = 200;
}
It accesses the MenuItem but not the image and I get an error message:
The object of type "System.Windows.Controls.MenuItem" cannot be converted to type "System.Windows.Controls.Image".
My Question is:
How can I access the image object?
You can just reference the image by name
private void ImageHeight200_Click(object sender, RoutedEventArgs e)
{
Image1.Height = 200;
}
You could use PlacementTarget property of ContextMenu
private void ImageHeight200_Click(object sender, System.Windows.RoutedEventArgs e){
MenuItem mnu = sender as MenuItem;
Image sp = null;
if(mnu!=null)
{
sp = ((ContextMenu)mnu.Parent).PlacementTarget as Image;
}}

Custom context menu for WPF WebBrowser Control

Hi I need to create a custom context menu for a web browser control in wpf. Here is my xaml code which is not working:
<WebBrowser x:Name="EmailBox" ap:BrowserBehavior.HtmlString="{Binding Message, Mode=OneWay}">
<WebBrowser.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy" Command="ApplicationCommands.Copy"/>
<MenuItem Header="Copy to Customer Reference ID"
Command="{Binding CopyID}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}},
Path=PlacementTarget.Selection.Text}">
<MenuItem.Icon>
<Image Source="{StaticResource CopyImageSource}" Width="16" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Copy to Comments"
Command="{Binding CopyToCommentsCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}},
Path=PlacementTarget.Selection.Text}">
<MenuItem.Icon>
<Image Source="{StaticResource NoteCopyI}" Width="16" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</WebBrowser.ContextMenu>
</WebBrowser>
I copied the context menu code from somewhere else. This works in other controls but not for the webbrowser control. Is it possible to make this work?
Hi You have to add reference to Microsoft HTML Object Library and than...
XAML
<Window x:Class="WPFCustomContextMenuInWebBrowser.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFCustomContextMenuInWebBrowser"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ContextMenu x:Key="MnuCustom" StaysOpen="True">
<MenuItem Header="Custom 1"></MenuItem>
<MenuItem Header="Custom 1"></MenuItem>
<MenuItem Header="Custom 3"></MenuItem>
</ContextMenu>
</Window.Resources>
<Grid>
<WebBrowser x:Name="Wb"></WebBrowser>
</Grid>
</Window>
C#
using System.Windows.Controls;
using MSHTML;
namespace WPFCustomContextMenuInWebBrowser {
public partial class MainWindow {
private HTMLDocumentEvents2_Event _docEvent;
public MainWindow() {
InitializeComponent();
Wb.Navigate("http://google.com");
Wb.LoadCompleted += delegate {
if (_docEvent != null) {
_docEvent.oncontextmenu -= _docEvent_oncontextmenu;
}
if (Wb.Document != null) {
_docEvent = (HTMLDocumentEvents2_Event)Wb.Document;
_docEvent.oncontextmenu += _docEvent_oncontextmenu;
}
};
}
bool _docEvent_oncontextmenu(IHTMLEventObj pEvtObj) {
WbShowContextMenu();
return false;
}
public void WbShowContextMenu() {
ContextMenu cm = FindResource("MnuCustom") as ContextMenu;
if (cm == null) return;
cm.PlacementTarget = Wb;
cm.IsOpen = true;
}
}
}
No, It's not possible to make this work.
WebBrowser control is a very thin wrapper around native WebBrowser ActiveX component, which is a part of Internet Explorer subsystem. It is hosted in it's own window host (WPF window and WebBrowser have different HWNDs), so WPF knows only about focus entering and leaving WebBrowser, but has no knowledge of any keyboard/mouse events. Also, there is so called 'airspace problem': WPF-rendered and native regions of screen area cannot overlap.
Therefore you cannot use WPF ContextMenu with WebBrowser, because:
WPF doesn't recieve Mouse Right Click event to open Context Menu
WPF cannot draw Context Menu above WebBrowser
Also, I don't think there is easy way to emulate ContextMenu with html/js in browser's content - as I recall, ActiveX component uses IE5 (quirk) rendering mode, and it is not possible to change that without changing registry files.
You can try to use ActiveX API with WebBrowser.Document object to disable native context menu and draw another one yourself through WinAPI, which is not an easy task.
So, I would recommend to look for other, pure-WPF browser controls or HTML renderers, such as awesomium
The XAML as follows:
<!--WebBrowser to Display Chat Messages-->
<WebBrowser Name="webBrowser"
Source="http://stakoverflow.com"
Navigated="webBrowser_Navigated"
Navigating="webBrowser_Navigating"
LoadCompleted="webBrowser_LoadCompleted">
<WebBrowser.ContextMenu>
<ContextMenu x:Name="wbContextMenu" >
<MenuItem x:Name="menuItem1" Header="Test Item" Click="menuItem1_Click" />
</ContextMenu>
</WebBrowser.ContextMenu
</WebBrowser>
Code as follows:
using mshtml;
private mshtml.HTMLDocumentEvents2_Event documentEvents;
in constructor or xaml set your LoadComplete event:
webBrowser.LoadCompleted += webBrowser_LoadCompleted;
then in that method create your new webbrowser document object and view the available properties and create new events as follows:
private void webBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
documentEvents = (HTMLDocumentEvents2_Event)webBrowserChat.Document; // this will access the events properties as needed
documentEvents.oncontextmenu += webBrowserChat_ContextMenuOpening;
}
private bool webBrowserChat_ContextMenuOpening(IHTMLEventObj pEvtObj)
{
wbContextMenu.PlacementTarget = pEvtObj as ContextMenu; // Creates target spot where contextmenu will appear
wbContextMenu.IsOpen = true; // Opens contextmneu
return false; // ContextMenu wont open
// return true; ContextMenu will open
// Here you can create your custom contextmenu or whatever you want
}
I've taken the solution provided by #MartinHoly and i've encountered the problem: to context menu can be popped up only once (if you right-click on the scrollbar, for example, or select a custom menu item - next time you right-click the WebBrowser brings the standard IE menu). I have made the following workaround:
The xaml:
<Window x:Class="WPFCustomContextMenuInWebBrowser.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFCustomContextMenuInWebBrowser"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ContextMenu x:Key="MnuCustom" StaysOpen="True">
<MenuItem Header="Custom 1"></MenuItem>
<MenuItem Header="Custom 2"></MenuItem>
<MenuItem Header="Custom 3"></MenuItem>
</ContextMenu>
</Window.Resources>
<Grid>
<WebBrowser x:Name="Browser"></WebBrowser>
</Grid>
The code behind:
using System.Windows.Controls;
using MSHTML;
namespace WPFCustomContextMenuInWebBrowser {
public partial class MainWindow {
public MainWindow()
{
InitializeComponent();
Browser.LoadCompleted += BrowserOnLoadCompleted;
}
void BrowserOnLoadCompleted(object sender, NavigationEventArgs navigationEventArgs)
{
var mshtmlDoc = Browser.Document as HTMLDocument;
if (mshtmlDoc == null) return;
var doc2event = mshtmlDoc as HTMLDocumentEvents2_Event;
if (doc2event != null)
{
doc2event.onfocusin += FocusInContextMenu;
}
}
bool OpenContextMenu(IHTMLEventObj pEvtObj)
{
WbShowContextMenu(pEvtObj as ContextMenu);
return false;
}
void FocusInContextMenu(IHTMLEventObj pevtobj)
{
var mshtmlDoc = Browser.Document as HTMLDocument;
var doc2event = mshtmlDoc as HTMLDocumentEvents2_Event;
if (doc2event != null)
{
doc2event.oncontextmenu -= OpenContextMenu;
doc2event.onfocusin -= FocusInContextMenu;
doc2event.oncontextmenu += OpenContextMenu;
doc2event.onfocusin += FocusInContextMenu;
}
}
public void WbShowContextMenu()
{
ContextMenu cm = FindResource("MnuCustom") as ContextMenu;
if (cm == null) return;
cm.PlacementTarget = Browser;
cm.IsOpen = true;
}
}
}
I have a indirect implementation, which involves calling each other in C# and javascript.
xaml:
<WebBrowser x:Name="webbrowser">
<WebBrowser.ContextMenu>
<ContextMenu>
<MenuItem Header="item1"/>
</ContextMenu>
</WebBrowser.ContextMenu>
</WebBrowser>
c#:
using System.Runtime.InteropServices;
public MainWindow()
{
InitializeComponent();
//webbrowser.Navigate(new Uri("https://www.google.com"));
webbrowser.ObjectForScripting = new ScriptManager(this);
webbrowser.LoadCompleted += Webbrowser_LoadCompleted;
}
private void Webbrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
//call C# method and disable the default contextmenu here.
webbrowser.InvokeScript("eval", new object[] { "document.oncontextmenu = function() { window.external.ShowContextMenu(); return false; };" });
}
[ComVisible(true)]
public class ScriptManager
{
private MainWindow mainWindow;
public ScriptManager(MainWindow MainWindow)
{
mainWindow = MainWindow;
}
public void ShowContextMenu()
{
mainWindow.webbrowser.ContextMenu.IsOpen = true;
}
}
But it still has a native contextmenu when page is loading because LoadCompleted event hasn't triggered.
So if the html page is writed by self, you can add this line directly to the script section in html and don't need the LoadCompleted event:
document.oncontextmenu = function() { window.external.ShowContextMenu(); return false; };

MenuItem with dynamic MenuItems

I have this MenuBar in my application:
<Menu Grid.Row="0" Height="22" Name="menu1" HorizontalAlignment="Stretch" VerticalAlignment="Top" >
<MenuItem Header="File" />
<MenuItem Header="Youtube">
</MenuItem>
<MenuItem Header="Help" />
</Menu>
And i want to add items to the Youtube MenuItem dynamic ,something like this:
MenuItem menu = (MenuItem)sender;
ItemCollection items = menu.Items;
items.Clear();
if (YouTubeAuth.CreateInstance().IsLogin())
{
MenuItem refreshItem = new MenuItem();
refreshItem.Header = "Refresh";
refreshItem.Click += DidPressRefresh;
items.Add(refreshItem);
MenuItem logouttItem = new MenuItem();
logouttItem.Header = "Signout";
logouttItem.Click += DidPressLogout;
items.Add(logouttItem);
}
else
{
MenuItem loginItem = new MenuItem();
loginItem.Header = "Login";
loginItem.Click += DidPressLogin;
items.Add(loginItem);
}
It say if you login show logout and refresh otherwise shot login.
I try to add this method to Click="DidPressDeleteAllFavorites" of the Youtube MenuItem but it won't work.
Any idea how to fix it? what i do wrong?
if you are using the MVVM-pattern
<MenuItem Header="Youtube" ItemsSource="{Binding yourProperty}"/>
if you are working with code-behind
XAML
<MenuItem Header="Youtube" Name="myYoutube"/>
Code-behind
myYoutube.ItemsSource=yourMenuItems;
EDIT
the problem in your code is in my opinion you just need to call your Event Code on on startup because your Youtube has no subMenuitem on begin or you could also call UpdateLayout() in your event this could also maybe fix it
Working Example
Codebehind
public partial class MainWindow : Window
{
bool test = false;
public MainWindow()
{
InitializeComponent();
MenuItem_Click(myYouTube, null);
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
var mymenuitem = sender as MenuItem;
MenuItem menu = (MenuItem)sender;
ItemCollection items = menu.Items;
items.Clear();
if (test)
{
MenuItem refreshItem = new MenuItem();
refreshItem.Header = "Refresh";
//refreshItem.Click += DidPressRefresh;
items.Add(refreshItem);
MenuItem logouttItem = new MenuItem();
logouttItem.Header = "Signout";
//logouttItem.Click += DidPressLogout;
items.Add(logouttItem);
test = false;
}
else
{
MenuItem loginItem = new MenuItem();
loginItem.Header = "Login";
//loginItem.Click += DidPressLogin;
items.Add(loginItem);
test = true;
}
}
}
XAML
<Menu Height="23" HorizontalAlignment="Left" Margin="84,66,0,0" Name="menu1" VerticalAlignment="Top" Width="200">
<MenuItem Header="File" />
<MenuItem Header="Youtube" Name="myYouTube" Click="MenuItem_Click">
</MenuItem>
<MenuItem Header="Help" />
</Menu>

wpf context menu left-click

Is it possible to attach context menu to a wpf control and have it opened on left-click (as opposed to more customary right-click)? I want to achieve that using xaml only (this should be a part of my control's view template).
Here is a way to show context menu on left-click:
Create a new left button handler on the Border element:
<Border x:Name="Win"
Width="40"
Height="40"
Background="Purple"
MouseLeftButtonUp="UIElement_OnMouseLeftButtonUp">
and then add this:
private void UIElement_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
var mouseDownEvent =
new MouseButtonEventArgs(Mouse.PrimaryDevice,
Environment.TickCount,
MouseButton.Right)
{
RoutedEvent = Mouse.MouseUpEvent,
Source = Win,
};
InputManager.Current.ProcessInput(mouseDownEvent);
}
What it does, it basically maps the left-click into right-click. For reusability, you can wrap this into an attached behavior.
Here is how I would do a simple example of what I am suggesting:
The XAML:
<Window x:Class="LeftClickMenu.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow">
<Grid>
<Border Width="400" Height="300" Background="#ccc" BorderBrush="#333"
BorderThickness="1"
MouseLeftButtonDown="Border_MouseLeftButtonDown"
MouseRightButtonUp="Border_MouseRightButtonUp">
<Border.ContextMenu>
<ContextMenu x:Name="myContextMenu">
<MenuItem Header="Menu Item 1" />
<MenuItem Header="Menu Item 2" />
<MenuItem Header="Menu Item 3" />
<MenuItem Header="Menu Item 4" />
<MenuItem Header="Menu Item 5" />
</ContextMenu>
</Border.ContextMenu>
</Border>
</Grid>
</Window>
And the code-behind:
using System.Windows;
using System.Windows.Input;
namespace LeftClickMenu
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
myContextMenu.IsOpen = true;
}
private void Border_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
}
}
I also added the extra MouseRightButtonUp event to inhibit the right-click popup of the context menu.
Create a method to programmatically open a submenu as stated in this SO article:
Show menu programmatically in WPF
Create an event for LeftMouseButtonDown and call that event in XAML.

RelayCommand not firing on MenuItem click WPF MVVM

I have a menu item on my WPF form that runs an import routine, I have bound the command property to a ICommand property in my view model but for some reason the method won't fire.
This is the xaml:
<Menu Height="21"
Margin="0,-2,0,0"
VerticalAlignment="Top"
Grid.ColumnSpan="2">
<MenuItem Header="File" Command="{Binding ImportFileCommand}">Import</MenuItem>
</Menu>
And this is in my view model:
private ICommand importfilecommand;
public ICommand ImportFileCommand
{
get
{
if (this.importfilecommand == null)
{
this.importfilecommand = new RelayCommand(parm => ImportFile());
}
return this.importfilecommand;
}
}
private void ImportFile()
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "Tab Files (*.tab)|*.tab*";
if (dialog.ShowDialog() == true)
{
// MessageBox.Show(dialog.FileName);
}
}
This is the pattern that I have used for all my buttons on the form but the menu item just won't work. Am I missing something or do menu items have to be done differently?
Thanks.
Change your XAML to
<Menu Height="21" Margin="0,-2,0,0" VerticalAlignment="Top" Grid.ColumnSpan="2">
<MenuItem Header="File">
<MenuItem Header="Import" Command="{Binding ImportFileCommand}" />
</MenuItem>
</Menu>
In your example, the "Import" content of the MenuItem element implicitly creates a child MenuItem of the parent File MenuItem. This child MenuItem has no Command property defined and so is unable to be executed. Apparently the executability of the Command defined on the parent MenuItem is overridden by the sub-menu expansion functionality.

Categories

Resources