How to implement custom context menu in WPF WebView - wpf

I'm able to implement a WPF ContextMenu on other controls, but it doesn't seem to work on a WebView (Microsoft.Toolkit.Wpf.UI.Controls.WebView).
At the top of the view's XAML, I have the ContextMenu as a StaticResource:
<UserControl.Resources>
<ContextMenu x:Key="cmBrowser" IsEnabled="True" >
<MenuItem Header="Get 1 and 2" />
<Separator />
<MenuItem Header="Get 1" />
<MenuItem Header="Get 2" />
</ContextMenu>
</UserControl.Resources>
Lower in the view, it is implemented on a Label, and it works as expected:
<Label Content="Browser"
ContextMenu="{StaticResource cmBrowser}"
Style="{StaticResource WidgetTitleStyle}"
Grid.Row="0" Grid.Column="0" />
However, it doesn't work on the WebView control, implemented as follows:
<wbv:WebView x:Name="browser"
ContextMenu="{StaticResource cmBrowser}" />
I've tried mucking about in the code-behind, but even events like MouseRightButtonDown/Up aren't firing.
Any advice on how to resolve?

Related

Is Touch supported in ContextMenu in DataGrid in WPF app?

I have a DataGrid in my WPF application. I have defined a ContextMenu for the rows in the grid. When we right click on the grid's row, context menu appears but it doesn't come up when we "hold & press" on a touch support device (i.e. tablet with Windows 7). I have set IsManipulation=true in my grid.
<UserControl.Resources>
<ContextMenu x:Shared="False" x:Key="contextDailyPlannerMenu">
<MenuItem Command="{Binding ViewCustomerCommand}" Header="View Customer" />
<MenuItem Command="{Binding DisplayOrderCommand}" Header="Order Guide" />
</ContextMenu>
</UserControl.Resources>
<DataGrid x:Name="DailyPlannerGridView" ItemsSource="{Binding ListDailyPlanner}" ContextMenu="{StaticResource contextDailyPlannerMenu}" HIsManipulationEnabled="True" IsReadOnly="True" >
Will touch be supported by default? If not, how to achieve this?
Thanks.

Bind Command for MenuItem in DataTemplate without Tag

I want to bind a command in my ViewModel to a menuItem which is in DataTemplate. I can do that with using Tag. Is there any method which can do the same task but without using tag.
<Window.Resources>
<DataTemplate x:Key="StudentListBoxItemTemplate">
<StackPanel Tag="{Binding DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}">
<TextBlock Text="{Binding Name}"/>
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Trigger" Command="{Binding PlacementTarget.Tag.TriggerCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListBox
ItemsSource="{Binding StudentList}"
ItemTemplate="{StaticResource StudentListBoxItemTemplate}">
</ListBox>
</StackPanel>
My ViewModel
public class MainViewModel {
public ICommand TriggerCommand { ... }
public ObservableList<Student> StudentList { ... }
}
With your current design, you need to get from the ContextMenu through the StackPanel and back to the DataContext of the containing ListBox. What makes this awkward is that the DataContext of the StackPanel is already narrowed down to a particular student.
There are at least two ways to make this easier:
Provide a TriggerCommand property in Student so the command is right there where you need it
Provide a Parent property in the Student to escape the narrowed scope
You can try to add click event to the menuItem like following
<Menu Style="{StaticResource bellRingersFontStyle}" Height="23" Name="menu1" Width="Auto" DockPanel.Dock="Top" VerticalAlignment="Top">
<MenuItem Header="_File">
<MenuItem Header="_New Member" Name="newMember" Click="newMember_Click" >
<MenuItem.Icon>
<Image Source="Face.bmp" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="_Save Member Details" Name="saveMember" IsEnabled="False" Click="saveMember_Click">
<MenuItem.Icon>
<Image Source="Note.bmp" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="E_xit" Name="exit" Click="exit_Click" />
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About Middleshire Bell Ringers" Name="about" Click="about_Click" >
<MenuItem.Icon>
<Image Source="Ring.bmp" />
</MenuItem.Icon>
</MenuItem>
</MenuItem>
</Menu>
Try binding the command to Click. My VS is down so can't check at this moment.
One way would be to get the context menu collection presentation defined in your viewmodel, which will contain the header string and command action (maybe with predicate).
The viewmodel creates an observable collection of the contextmenu items and the view binds that to ContextMenu itemssource and sets the displaymember path to header string.

wpf how to update Window

I have made my application multilingual. It changes it's language when you click the corresponding menuitem. This works fine but my problem comes when my parent window doesn't change it's language (menu is in parent window). All child windows change their language. Is there any way to force window to load again? I have done my application with resx-files and also checked that Thread.CurrentThread.CurrentCulture and Thread.CurrentThread.CurrentUICulture are changed when menuitem is clicked.
Edit:
I have made my own class to do the multilingual part and it is an adaptation from this article's approach: WPF Runtime Localization, it works. Here is a part of my XAML code to show the databindings:
<Window x:Class="Multilingual.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:Multilingual.Properties"
Height="350" Width="300" Name="mainWindow" ResizeMode="CanMinimize" SizeToContent="Manual" Closing="mainWindow_Closing" KeyDown="mainWindow_KeyDown">
and
<Menu Height="22" Name="menu" Width="{Binding ElementName=mainWindow, Path=Width}" HorizontalAlignment="Left" VerticalAlignment="Top" Background="Snow" BorderThickness="2">
<Menu.BitmapEffect>
<DropShadowBitmapEffect />
</Menu.BitmapEffect>
<MenuItem Header="{x:Static properties:Resources.Menu}">
<MenuItem Header="{x:Static properties:Resources.Language}" >
<MenuItem Header="{x:Static properties:Resources.Deutsch}" Name="itemDeutsch" Click="menuItem_Click" />
<MenuItem Header="{x:Static properties:Resources.English}" Name="itemEnglish" Click="menuItem_Click" />
</MenuItem>
<MenuItem Header="{x:Static properties:Resources.Exit}" Click="itemExit_Click"/>
</MenuItem>
</Menu>
So I think it would be enough if I would be able to update the window somehow.
WPF: How to change the CurrentUICulture at runtime
I found a solution. I changed my databindings to look like this:
<MenuItem Header="{Binding Path=Menu, Source={StaticResource Resources}}">
Where "Menu" corresponds the MenuItem's name in resx-file.

WPF ToolBar Separator shrinks to nothing when inside a StackPanel

Given the very simple wpf app
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="800">
<Grid>
<ToolBar Height="50" >
<MenuItem Header="Test1" />
<MenuItem Header="Test2" />
<StackPanel Orientation="Horizontal">
<Separator />
<MenuItem Header="Test3" />
<MenuItem Header="Test4" />
<MenuItem Header="Test5" />
</StackPanel>
</ToolBar>
</Grid>
</Window>
The Separator element shrinks to nothing. If I put the Separator just before the StackPanel begins, it will show up. Why does this happen? Is there a style setting that can be applied somewhere to avoid this?
The StackPanel is changing the orientation of the Separator somehow. Note that if you explicitly tell the Separator to be 20 units wide, the Separator will be a horizontal line instead of a vertical line. That's part of what's going on.
If you apply a LayoutTransform to the Separator, it undoes whatever the StackPanel is doing.
<Separator>
<Separator.LayoutTransform>
<RotateTransform
Angle="90" />
</Separator.LayoutTransform>
</Separator>
I don't understand the need for a StackPanel, though.
Separators default to Horizontal orientation.
Separators placed directly inside a ToolBar have their styles changed, because Toolbar overrides the default styles of its items. Separators placed elsewhere get the default style of a separator. So you will need to style the separator yourself if you vwant to keep it inside the StackPanel.
This CodeProject discussion includes sample code for accomplishing this.
Reference: WPF Unleashed by Adam Nathan, page 117.
ToolBars are funny about what you put inside. They get funny when all the elements aren't direct children of the ToolBar. The grouping elements are ToolBarTray (group of toolbars), ToolBar, and ToolBarPanel (logical, for collapsing overflow). This is what WPF wants to see:
<Grid>
<ToolBarTray>
<ToolBar Height="Auto">
<ToolBarPanel Orientation="Horizontal" ToolBar.OverflowMode="AsNeeded"/>
<MenuItem Header="Test1" />
<Separator/>
<MenuItem Header="Test2" />
</ToolBar>
<ToolBar Height="Auto">
<ToolBarPanel ToolBar.OverflowMode="Never"/>
<MenuItem Header="Test3" />
<MenuItem Header="Test4" />
<Separator/>
<MenuItem Header="Test5" />
<ToolBarPanel ToolBar.OverflowMode="AsNeeded"/>
<MenuItem Header="Test6" />
<MenuItem Header="Test7" />
</ToolBar>
</ToolBarTray>
</Grid>

WPF Focus Navigation Wrapping

Is there a way to force Focus Navigation (as controlled by the Tab key or MoveFocus method) to wrap inside a given container? I have included code which demonstrates this problem below. What is the easiest way to make Tab move focus from TextBox "Charlie" to TextBox "Able" (and visa-versa for Shift+Tab on TextBox "Able") rather than moving it to MenuItem "Alpha"?
<Window x:Class="NavWrapExample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<DockPanel LastChildFill="True">
<Menu DockPanel.Dock="Top">
<MenuItem Header="Alpha" />
<MenuItem Header="Bravo" />
<MenuItem Header="Charlie" />
</Menu>
<StackPanel>
<TextBox Text="Able" />
<TextBox Text="Baker" />
<TextBox Text="Charlie" />
</StackPanel>
</DockPanel>
</Window>
Use the KeyboardNavigation.TabNavigation attached property, like so:
<StackPanel KeyboardNavigation.TabNavigation="Cycle">
<TextBox Text="Able" />
<TextBox Text="Baker" />
<TextBox Text="Charlie" />
</StackPanel>
Found the answer on Mark Smith's blog.
It sounds like what you want is the same behavior as toolbars: you can tab into them, but once an element within the toolbar gets keyboard focus, focus loops inside. If so, use FocusManager as follows:
<StackPanel FocusManager.IsFocusScope="True">
<!-- Controls go here... -->
</StackPanel>

Resources