Implementing an Edit menu in MVVM Light application - c#

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.

Related

Passing a command to a mainwindow from a different viewmodel

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.

Binding to other controlls InputBindings

I would like to Bind Keybindings of my Button to the Keybindings of my Window.
My Window (Name="Mainwindow) Input Binding:
<Window.InputBindings>
<KeyBinding Key="Return" Command="{Binding KeyPressed}" CommandParameter="Next"/>
</Window.InputBindings>
My idea of what the Button should look like
<Button Content="Select Directory" Command="{Binding BrowseDirectory}">
<Button.InputBindings>
<KeyBinding Key="Return" Command="{Binding ElementName=Mainwindow, Path=InputBindings}"/>
</Button.InputBindings>
</Button>
Sadly the Outwindow did not display any kind of Binderror any anything else to give me a clue on why it is not working.
So baisically the question is: How can I Bind the Control.InputBindings to another Control.InputBindings?
Why don't you just bind the Command property to the same source property:
<Button Content="Select Directory" Command="{Binding BrowseDirectory}">
<Button.InputBindings>
<KeyBinding Key="Return" Command="{Binding Path=DataContext.KeyPressed, RelativeSource={RelativeSource AncestorType=Window}}"/>
</Button.InputBindings>
</Button>

Shortcuts not working in UserControl

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>

My menu showing up at the top left of the screen

I built a menu bar using the menu control in WPF and it had been working but at some point the menu started showing up on the top left of my first monitor regardless of where in the screen I had the window. Even if I move the main window to the second monitor the menu still shows up in the first monitor.
Here is the code for the menu control:
<Menu>
<MenuItem Header="_File">
<MenuItem Header="_New" Command="New" InputGestureText="Ctrl+N"/>
<MenuItem Header="_Open" Command="Open" InputGestureText="Ctrl+O" />
<MenuItem Header="_Close" Command="Close" InputGestureText="Ctrl+W" />
<Separator/>
<MenuItem Header="_Save" Command="Save" InputGestureText="Ctrl+S" />
<MenuItem Header="Save _As" Command="SaveAs" InputGestureText="Ctrl+Shift+S" />
<Separator/>
<MenuItem Header="E_xit" Command="{StaticResource CommandBinding_Exit}" InputGestureText="Ctrl+Q" />
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Header="_Add" Command="{StaticResource CommandBinding_Add}" InputGestureText="" />
<MenuItem Header="_Edit" Command="{StaticResource CommandBinding_Edit}" InputGestureText="" />
<MenuItem Header="_Delete" Command="Delete" InputGestureText="" />
<Separator/>
<MenuItem Header="Cut" Command="Cut" InputGestureText="Ctrl+X" />
<MenuItem Header="Copy" Command="Copy" InputGestureText="Ctrl+C" />
<MenuItem Header="Paste" Command="Paste" InputGestureText="Ctrl+V" />
</MenuItem>
<MenuItem Header="_View">
<MenuItem x:Name="miShowStatusBar" Header="Show Status Bar" IsCheckable="True" IsChecked="True" Click="miShowStatusBar_Click"/>
<MenuItem x:Name="miShowFullPath" Header="Show Full Path" IsCheckable="True" IsChecked="True" Click="miShowFullPath_Click"/>
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About"/>
</MenuItem>
</Menu>
The menu is not referenced any where in the code behind so I can't figure out what might be causing this odd menu placement.
I think the source of the OP's problem is in the search box under the MenuBar. It may come from the Margin or Width settings of the search box.
I faced the same problem and found the sources. Here is the boilerplate code to reproduce the same error. The problem is a combination of 5 parts, as shown in the following XAML. Remove any one of them will solve the OP's issue.
You need to bind the XAML View to a ViewModel with public property Films. If the Films collection has any element in it, it will also cause the issue (Part 5).
<Grid x:Name="MainContent">
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid >
<Menu>
<MenuItem Header="Film">
<MenuItem Header="New"/>
</MenuItem>
</Menu>
</Grid>
<Grid Grid.Row="1">
<Grid>
<!--Part 1: Remove HorizontalScrollBarVisibility="Auto"-->
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<!--Part 2: Remove ItemsSource="{Binding Films}"-->
<ItemsControl ItemsSource="{Binding Films}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<!--Part 3: Remove the setter tag-->
<Setter Property="Margin" Value="2" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button>
<Button.Template>
<ControlTemplate TargetType="Button">
<!--Part 4: Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=ActualWidth}-->
<ContentPresenter Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=ActualWidth}"/>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
</Grid>
This has nothing to do with WPF. It's a possible corruption of the Handedness setting or driver issues if you have a touch screen monitor, tablet PC or have a tablet attached with a bad driver (such as a Wacom drawing tablet).
Type this into the Run dialog: shell:::{80F3F1D5-FECA-45F3-BC32-752C152E456E}.
Once Tablet PC Settings come up, go to the Other tab and in the Handedness section, check the Left Handed option.
I bet that this has something to do with the Xaml-Designer of your Visual Studio instance. I encounter similar strange things because of leaving the Xaml-Designer open while debugging.
Try to kill the XDesProc.exe process and check if the problem still occurs.

KeyBinding for gestures CTRL+C and CTRL+ V do not work?

I have a few ICommands in my View Model which I would like to bind them using Key Board bindings to my user control. The problem I am facing is that they are not fired when I use CTRL + C and CTRL + V to bind my copy and paste commands in my UserControl. Am I supposed to override them or something?.
<UserControl.InputBindings>
<KeyBinding Gesture="CTRL+C" Command="{Binding CopyCommand}" />
</UserControl.InputBindings>
This works for me like a charm:
<!--COPY-->
<UserControl.InputBindings>
<KeyBinding Key="C" Modifiers="Ctrl" Command="{Binding CopyToStackCommand}" />
</UserControl.InputBindings>
<!--PASTE-->
<UserControl.InputBindings>
<KeyBinding Key="V" Modifiers="Ctrl" Command="{Binding PasteFromStackCommand}" />
</UserControl.InputBindings>
<KeyBinding Key="C" Modifiers="Ctrl" Command="Copy" CommandParameter="{Binding copy}" />

Categories

Resources