I have a UserControl, which has CommandBindings:
<UserControl x:Class="DbCreator.UserControls.Menu"
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:local="clr-namespace:DbCreator"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.CommandBindings>
<CommandBinding Command="SelectAll" Executed="SelectAllCommand_Executed"/>
<CommandBinding Command="local:MyCommands.ToggleNavigator" Executed="ToggleNavigatorCommand_Executed"/>
<CommandBinding Command="local:MyCommands.ToggleGrid" Executed="ToggleGridCommand_Executed"/>
<CommandBinding Command="local:MyCommands.SelectNone" Executed="SelectNoneCommand_Executed"/>
</UserControl.CommandBindings>
<Menu Background="White">
<MenuItem Header="_Файл"/>
<MenuItem Header="_Правка">
<MenuItem Header="Выделить всё" Command="SelectAll"/>
<MenuItem Header="Убрать выделение" Command="local:MyCommands.SelectNone"/>
</MenuItem>
<MenuItem Header="_Вид">
<MenuItem x:Name="ToggleNavigator" Header="Скрыть навигатор" Command="local:MyCommands.ToggleNavigator"/>
<MenuItem x:Name="ToggleGrid" Header="Скрыть сетку" Command="local:MyCommands.ToggleGrid"/>
</MenuItem>
<MenuItem Header="_Диаграмма"/>
<MenuItem Header="_Справка"/>
</Menu>
When I click MenuItem, my Executed method is fired, but shortcuts not working. When this UserControl content was a part of MainWindow code, all shortcuts worked perfect. But I want to define menu in a separate file.
So the problem was that Menu was unfocused and didn't recieve input. Solution is to add InputBindings to MainWindow:
<Window.InputBindings>
<KeyBinding Command="SelectAll" CommandTarget="{Binding ElementName=Menu}" Key="A" Modifiers="Control"/>
<KeyBinding Command="local:MyCommands.SelectNone" CommandTarget="{Binding ElementName=Menu}" Key="A" Modifiers="Control+Shift"/>
<KeyBinding Command="local:MyCommands.ToggleNavigator" CommandTarget="{Binding ElementName=Menu}" Key="N" Modifiers="Alt"/>
<KeyBinding Command="local:MyCommands.ToggleGrid" CommandTarget="{Binding ElementName=Menu}" Key="G" Modifiers="Alt"/>
</Window.InputBindings>
Related
I'm new to WPF and learning more about MVVM, and I've come across a problem. So I have my mainwindow.xaml with its code and implementation mostly based on the view model FileMenuCommands, now I've created another view model called AboutMenuCommands and I want to pass a command (the help command) from here to the main window, but when I try to do that the compiler doesn't find my function.
What do I need to do in order to pass a command from another view model in an XAML?
Code from mainWindow:
<Window x:Class="Notepad___.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:Notepad___.ViewModel"
mc:Ignorable="d"
Title="Notepad+++" Height="450" Width="800">
<Window.DataContext>
<local:FileMenuCommands/>
</Window.DataContext>
<Window.InputBindings>
<KeyBinding Key="O" Modifiers="Ctrl" Command="{Binding Path=Open}" />
<KeyBinding Key="N" Modifiers="Ctrl" Command="{Binding Path=New}" />
</Window.InputBindings>
<Grid>
<Menu Name="MainMenu" Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<MenuItem Header="_File" FontSize="14" >
<MenuItem Header="_New" InputGestureText="Ctrl+N" Command="{Binding Path=New}">
<MenuItem.ToolTip>
<ToolTip>Create a new file.</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
<MenuItem Header="Open" InputGestureText="Ctrl+O" Command="{Binding Path=Open}">
<MenuItem.ToolTip>
<ToolTip>Open a file.</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
<MenuItem Header="_Save" InputGestureText="Ctrl+S">
<MenuItem.ToolTip>
<ToolTip>Saves a file in the current location if it already exists, if not creates a prompt.</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
<MenuItem Header="_Save As" Command="{Binding Path=SaveAs}">
<MenuItem.ToolTip>
<ToolTip>Saves the file in the location prompted by the user in the format they desire.</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
<MenuItem Header="_Exit" InputGestureText="Ctrl+X">
<MenuItem.ToolTip>
<ToolTip>Exits the application.</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
</MenuItem>
<MenuItem Header="_Search" FontSize="14" >
<MenuItem Header="_Find" InputGestureText="Ctrl+F">
<MenuItem.ToolTip>
<ToolTip>Finds the occurences of the input word / set of characters.</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
<MenuItem Header="_Replace" InputGestureText="Ctrl+R">
<MenuItem.ToolTip>
<ToolTip>Replaces the input word / set of characters.</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
<MenuItem Header="_Replace All" >
<MenuItem.ToolTip>
<ToolTip>Replaces all the occurences of the input word / set of characters.</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
</MenuItem>
<MenuItem Header="_Help" FontSize="14" Command="{Binding Source=Help}"> // this is where i'm trying to pass my command from another xaml
<MenuItem Header="_About" >
<MenuItem.ToolTip>
<ToolTip>A few words about the application and who made it</ToolTip>
</MenuItem.ToolTip>
</MenuItem>
</MenuItem>
</Menu>
AboutMenuCommand.cs
using Notepad___.View;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Input;
namespace Notepad___.ViewModel
{
class AboutMenuCommands
{
private ICommand m_help;
private void HelpPage(object parameter)
{
var aboutPage = new About();
aboutPage.ShowDialog();
}
public ICommand Help
{
get
{
if (m_help == null)
m_help = new RelayCommand(HelpPage);
return m_help;
}
}
}
}
Your MainWindowViewModel should get the viewmodel instance from your about page. The about command should be implemented in MainWindowViewModel and call the viewmodel from the About page.
I had such questions several month ago and came out with a mvvm framework which does really help to understand the principles of mvvm.
But i did not want to give up the control to a framework which i can not look into and so i found mvvmgen .
So take a look at the doc in mvvmgen and you will find the answer to your mvvm questions.
This is XAML codes.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Menu x:Name="Menu1">
<MenuItem x:Name="MenuItem1" Height="40" Header="File">
<MenuItem x:Name="MenuItem11" Header="Help"/>
<MenuItem x:Name="MenuItem12" Header="About"/>
<MenuItem x:Name="MenuItem13" Header="Exit"/>
</MenuItem>
</Menu>
</Grid>
</Window>
How to expand sub menus from code behind?
Question picture: https://prnt.sc/img9p6
You will need a MenuViewModel class that has a ObservalbleCollection of SubMenuViewModel(s).
This class will need a property for the IsOpen for The Menu. https://msdn.microsoft.com/en-us/library/system.windows.controls.menuitem.issubmenuopen(v=vs.110).aspx
You should not create the MenuItems in WPF. But bind the Itemssource to thies collection.
You then bind the IsOpen from the MenuItem to the MenuItems in WPF (ItemsTemplate)
WPF - How can I create menu and submenus using binding
I'm building a WPF application using MVVM Light. I've added a menu to my window that includes the standard File and Edit menus:
<Window x:Class="ParserEditor.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:ParserEditor"
xmlns:ignore="http://www.galasoft.ch/ignore"
xmlns:i="clr namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
mc:Ignorable="d ignore"
Closing="Window_Closing"
DataContext="{Binding Main, Source={StaticResource Locator}}"
Height="{Binding Height, Mode=TwoWay}"
MaxHeight="{Binding MaxHeight, Mode=TwoWay}"
MinHeight="{Binding MinHeight, Mode=TwoWay}"
MinWidth="450"
Width="450"
Title="{Binding WindowTitle}">
<Window.InputBindings>
<KeyBinding Command="{Binding NewParserCommand}" Gesture="CTRL+N" />
<KeyBinding Command="{Binding OpenParserCommand}" Gesture="CTRL+O" />
<KeyBinding Command="{Binding SaveParserCommand}" Gesture="CTRL+S" />
<KeyBinding Command="{Binding SaveParserAsCommand}" Gesture="ALT+A" />
<KeyBinding Command="{Binding ExitCommand}" Gesture="ALT+F4" />
<KeyBinding Command="{Binding ApplicationCommands.Undo}" Gesture="CTRL+Z" />
<KeyBinding Command="{Binding ApplicationCommands.Redo}" Gesture="CTRL+Y" />
<KeyBinding Command="{Binding ApplicationCommands.Cut}" Gesture="CTRL+X" />
<KeyBinding Command="{Binding ApplicationCommands.Copy}" Gesture="CTRL+C" />
<KeyBinding Command="{Binding ApplicationCommands.Paste}" Gesture="CTRL+V" />
<KeyBinding Command="{Binding ApplicationCommands.Delete}" Gesture="DEL" />
<KeyBinding Command="{Binding ApplicationCommands.SelectAll}" Gesture="CTRL+A" />
</Window.InputBindings>
<DockPanel Name="Dock">
<Menu IsMainMenu="true" DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_New..." InputGestureText="Ctrl-N" Command="{Binding NewParserCommand}" />
<MenuItem Header="_Open..." InputGestureText="Ctrl-O" Command="{Binding OpenParserCommand}" />
<MenuItem Header="_Save..." InputGestureText="Ctrl-S" Command="{Binding SaveParserCommand}" />
<MenuItem Header="Save _As..." InputGestureText="Alt-A" Command="{Binding SaveParserAsCommand}" />
<Separator />
<MenuItem Header="E_xit" InputGestureText="Alt-F4" Command="{Binding ExitCommand}" />
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Header="Undo" InputGestureText="Ctrl-Z" />
<MenuItem Header="Redo" InputGestureText="Ctrl-Y" />
<Separator/>
<MenuItem Header="Cut" InputGestureText="Ctrl-X" />
<MenuItem Header="Copy" InputGestureText="Ctrl-C" />
<MenuItem Header="Paste" InputGestureText="Ctrl-V" />
<MenuItem Header="Delete" InputGestureText="Del" />
<MenuItem Header="Select All" InputGestureText="Ctrl-A" />
</MenuItem>
</Menu>
<Grid x:Name="LayoutRoot">
<!-- Some controls, including TextBlocks & TextBoxes here -->
</Grid>
</DockPanel>
</Window>
Now, if I run the application and make some edits in one of the TextBox controls, I can use the usual keyboard short cuts to cut, copy & paste text, undo & redo actions while in focus is the control. But if I click on my Edit menu and use one of my options there, nothing happens.
How do I get my menu items to work?
I figured this out. After posting the question & reviewing the XAML, I noticed that the Edit menu items didn't have any Commands bound to them. I added the required Command="ApplicationCommands.xxx" statements to the XAML & now the Edit menu works.
In my WPF application, I have a TextBox that has a KeyBinding and KeyTrigger on it, but it seems that the KeyTrigger is not invoked.
MainWindow.xaml
<Window
x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Title="MainWindow" Height="350" Width="525">
<TextBox>
<TextBox.InputBindings>
<KeyBinding Key="Return" Command="{Binding LogCommand}" CommandParameter="from KeyBinding"/>
</TextBox.InputBindings>
<i:Interaction.Triggers>
<ei:KeyTrigger Key="Return">
...
</ei:KeyTrigger>
</i:Interaction.Triggers>
</TextBox>
</Window>
Is there any way to invoke both of them? I want to do this because there is something I don't want to do in ViewModel.
Just put both in the interaction.Triggers part and remove the direct input bindings:
<TextBox>
<i:Interaction.Triggers>
<ei:KeyTrigger Key="Return">
<i:InvokeCommandAction Command="{Binding LogCommand}" CommandParameter="from KeyBinding"/>
...
</ei:KeyTrigger>
</i:Interaction.Triggers>
</TextBox>
I bind my textboxes to ViewModel class. But, button command (it's a RelayCommand, extended from ICommand) I bind to UsersView.xaml.cs. In UsersView.xaml.cs constructor I have this:
DataContext = UserVM;
btnAdd.DataContext = this;
This is how I bind button - it works.
<Button Command="{Binding Add}" Content="Add user" />
Now, I want to add KeyGesture for that button but I can't set DataContext for InputBindings and compiler can't find this Add command in UsersVM class.
<UsersView.InputBindings>
<KeyBinding Key="F10" Command="{Binding Add}" />
</UsersView.InputBindings>
I had this on a Window and this is the code I used...
<Window
x:Class="MVVMExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myViewModels="clr-namespace:MVVMExample"
Title="MainWindow"
x:Name="MyMainWindow"
Height="350"
Width="525">
Notice that I set the x.Name of the Window. Then in my KeyBinding, I did this...
<Window.InputBindings>
<KeyBinding
Key="F10"
Command="{Binding ElementName=MyMainWindow, Path=DataContext.AddPersonCommand}" />
</Window.InputBindings>
The AddPersonCommand is my ICommand from my ViewModel.