The Situation:
I have some Editing commands in WPF window, and a close command (Application.CloseCommand) and have some bindings like this
View:
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close"
Executed="CloseCommandBinding_Executed"/>
<CommandBinding Command="EditingCommands.ToggleBold"
Executed="EditingCommand_Executed"></CommandBinding>
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Key="Esc" Command="ApplicationCommands.Close"></KeyBinding>
</Window.InputBindings>
.. *Some panel and grid stuff and more things* ..
<RichTextBox Name="RTBPopup">
<RichTextBox.InputBindings>
<KeyBinding Key="Esc" Command="ApplicationCommands.Close"></KeyBinding>
</RichTextBox.InputBindings>
</RichTextBox>
.. *Some panel and grid stuff and more things* ..
<ToggleButton x:Name="btnToggleBold" CommandManager.Executed="EditingCommand_Executed" Command="EditingCommands.ToggleBold" CommandTarget="{Binding ElementName=RTBPopup}">B</ToggleButton>
Now:
If I press escape in RTBPopup (Richtextbox) the command gets executed and the debugger hits the breakpoint set on CloseCommandBinding_Executed method
but
when I click on toggle button for bold or press control + B, the EditingCommand_Executed is not getting hit by debugger (not getting executed)
What else I have tried:
<ToggleButton.CommandBindings>
<CommandBinding Command="EditingCommands.ToggleBold" Executed="EditingCommand_Executed"></CommandBinding>
</ToggleButton.CommandBindings>
Handle the PreviewExecuted event:
<CommandBinding Command="EditingCommands.ToggleBold"
PreviewExecuted="CommandBinding_PreviewExecuted" />
The command is handled by the RichTextBox so it never bubbles up to your parent Window.
You could also try to use the CommandManager to hook up the event handler programmatically:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CommandManager.AddPreviewExecutedHandler(RTBPopup, new ExecutedRoutedEventHandler(OnExecuted));
}
private void OnExecuted(object sender, ExecutedRoutedEventArgs e)
{
if(e.Command == EditingCommands.ToggleBold)
{
MessageBox.Show("fired!");
}
}
}
Related
I'm trying to add a WPF custom command to a control. What I've done:
XAML:
<Window x:Class="H.I.S.windows.CommandTest"
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:H.I.S.windows"
mc:Ignorable="d"
Title="CommandTest" Height="450" Width="800">
<Window.CommandBindings>
<CommandBinding Command="local:CustomCommand.Save" CanExecute ="SaveCommand_CanExecute" Executed="SaveCommand_Executed" />
</Window.CommandBindings>
<Grid>
<Button Command="local:CustomCommand.Save" Height="50" Width="100">Click me!</Button>
</Grid>
</Window>
C#:
namespace H.I.S.windows
{
public partial class CommandTest : Window
{
public CommandTest()
{
InitializeComponent();
}
private void SaveCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void SaveCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Saved");
}
}
public static class CustomCommand
{
public static readonly RoutedUICommand Save = new RoutedUICommand(
"Save",
"Save",
typeof(CustomCommand),
new InputGestureCollection()
{
new KeyGesture(Key.F2)
}
);
}
}
The button is disabled (even in design mode) and doesn't let the user click on it.
I've just implemented codes described HERE.
Where I'm wrong?
The code what you have posted throws me an error because of this below statement,
<Window.CommandBindings>
<CommandBinding Command="local:CustomCommand.Save" CanExecute ="CommandBinding_CanExecute" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
It started working for me after changing it to below,
<Window.CommandBindings>
<CommandBinding Command="local:CustomCommand.Save" CanExecute ="SaveCommand_CanExecute" Executed="SaveCommand_Executed" />
</Window.CommandBindings>
The event handlers in your code-behind are different from what you have in your xaml for CommandBinding.
"SaveCommand_CanExecute" and "SaveCommand_Executed"
After changing as above, it works for me and I can see the messagebox with "Saved" message when I hit click on it.
Hope you are not missing this. If something else stopping you then try to see if it shows any errors on further and let us know.
As #SirRufo suggested in question comments, Problem was that I declared "CommandBindings" for whole WPF window and button inside another control.
There are 2 solutions for this case:
1: Declaring CommandBindings for Button's direct parent.
2: Set name for control which is bound with command and add some code like below to control:
<Window ... x:Name = "windowName" ...>
<Window.CommandBindings>
<CommandBinding Command="custumCommand:CustomCommands.Save" CanExecute ="CommandBinding_CanExecute" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<Grid>
<StackPanel>
<GroupBox>
<Button Command="custumCommand:CustomCommands.Save" CommandTarget = "{Binding ElementName=windowName}" Content="Save" />
</GroupBox>
</StackPanel>
</Grid>
</Window>
Look at "CommandTarget" attribute of Button.
I know how to set default ApplicationCommands commands in WPF in order to enable simple cut, copy, and paste operations via ContextMenu. However I need to be able to do this in the code behind so that I can assign the commands dynamically as my TextBoxes are created.
How can I recreate this very simple WPF code in the code behind:
<TextBox x:Name="txtTagName" Style="{StaticResource TextBoxStyle}">
<TextBox.ContextMenu>
<ContextMenu Style="{StaticResource DefaultContextMenuStyle}">
<MenuItem x:Name="cmCut" Header="Cut" Command="ApplicationCommands.Cut" />
<MenuItem x:Name="cmCopy" Header="Copy" Command="ApplicationCommands.Copy" />
<MenuItem x:Name="cmPaste" Header="Paste" Command="ApplicationCommands.Paste" />
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
you could do something like:
this.cmCut.Command = ApplicationCommands.Cut;
How can I recreate this very simple WPF code in the code behind
Something like this, i.e. you programmatically create an instance of a TextBox and a ContextMenu and set the same properties that you set in your XAML markup:
TextBox textBox = new TextBox();
textBox.Style = FindResource("TextBoxStyle") as Style;
ContextMenu cm = new ContextMenu();
cm.Style = FindResource("DefaultContextMenuStyle") as Style;
cm.Items.Add(new MenuItem() { Header = "Cut", Command = ApplicationCommands.Cut });
cm.Items.Add(new MenuItem() { Header = "Copy", Command = ApplicationCommands.Copy });
cm.Items.Add(new MenuItem() { Header = "Paste", Command = ApplicationCommands.Paste });
textBox.ContextMenu = cm;
Good answer found here: How do I add a custom routed command in WPF?
I wanted to add custom inputs with my own commands for MenuItems and with appropriate texts for the commands displayed in the MenuItems. What solved my problem was to add both a command binding and an input binding section for the window there I could bind my command class and input to that command:
<Window x:Class="SomeNamespace.MainWindow"
<!--Other stuff here-->
xmlns:local="clr-namespace:SomeNamespace"
mc:Ignorable="d"
Title="MainWindow" Height="544" Width="800">
<Window.CommandBindings>
<CommandBinding Command="local:Commands.SomeCommand" Executed="CommandBinding_SomeCommand" />
<CommandBinding Command="local:Commands.SomeOtherCommand" Executed="CommandBinding_SomeOtherCommand" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="local:Commands.SomeCommand" Key="S" Modifiers="Ctrl" />
<KeyBinding Command="local:Commands.SomeOtherCommand" Key="O" Modifiers="Ctrl" />
</Window.InputBindings>
And then I could use it in my MenuItems like this (note that "InputGestureText" adds the shortcut/input text to the MenuItem):
<MenuItem Name="MenuItemSomeCommand" Command="local:Commands.SomeCommand" InputGestureText="Ctrl+S" />
<MenuItem Name="MenuItemSomeOtherCommand" Command="local:Commands.SomeOtherCommand" InputGestureText="Ctrl+O" />
Code for the "Commands" class (in my case in Commands.cs):
using System.Windows.Input;
namespace SomeNamespace
{
public static class Commands
{
public static readonly RoutedUICommand BuildFiles =
new RoutedUICommand("Some Command", "SomeCommand", typeof(MainWindow));
public static readonly RoutedUICommand BuildFiles =
new RoutedUICommand("Some Other Command", "SomeOtherCommand", typeof(MainWindow));
}
}
And code for the Executed binding command in MainWindow.xaml.cs:
public void CommandBinding_SomeCommand(Object sender, ExecutedRoutedEventArgs e)
{
// Add code that should trigger when the "SomeCommand" MenuItem is pressed
}
public void CommandBinding_SomeOtherCommand(Object sender, ExecutedRoutedEventArgs e)
{
// Add code that should trigger when the "SomeOtherCommand" MenuItem is pressed
}
The RichTextBox provides a lot of commands with accompanying key gestures.
However, when IsReadOnly=True is set, many of those commands do not make sense and do not take any action, e.g. Ctrl+I, Ctrl+R. Nevertheless, when a command in the Window uses one of the key gestures, the command in the Window does not fire when the RichtTextBox has focus:
<Window x:Class="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:"
mc:Ignorable="d">
<Window.CommandBindings>
<CommandBinding Command="local:MainWindow.MyCommand" Executed="MyCommandBinding_Executed" />
</Window.CommandBindings>
<StackPanel>
<RichTextBox Height="50" IsReadOnly="True" />
<CheckBox Content="This is a checkbox" />
<TextBlock Name="whatsGoingOn" />
</StackPanel>
</Window>
using System.Windows;
using System.Windows.Input;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public static RoutedUICommand MyCommand = new RoutedUICommand(
"My Command",
"MyCommand",
typeof(MainWindow),
new InputGestureCollection() { new KeyGesture(Key.R, ModifierKeys.Control) });
private void MyCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
whatsGoingOn.Text += ".";
}
}
Now maybe the right answer is “don’t use RichTextBox with IsReadOnly="True", use something else instead”, but let’s assume I had to or wanted to use RichTextBox.
What can I do to make key gestures fire my command even when the RichTextBox has focus?
You can intercept the keystrokes in the PreviewKeyDown event of the RichTextBox. Set the e.Handled member to true and that will prevent the actually processing of the keys.
Hope it helps
Being fairly new to C# and WPF, I'm currently designing a window and at the moment I'm working on the basic window logic to operate and function correctly. The problem I have is when a MenuItem is left clicked it does not register the left click, but will register a right click. The logic is programmatic.
WPF:
<Menu Grid.Row="0"
Background="LightGray"
Margin="0,40,0,0"
VerticalAlignment="Top"
Height="20">
<MenuItem Height="Auto"
Width="Auto"
Header="File">
<MenuItem Header=""/>
<Separator/>
<MenuItem x:Name="closeWindowMenu"
Header="Close"
MouseUp="button_MouseUp"/>
</MenuItem>
</Menu>
C#:
private void button_MouseUp(object sender, MouseEventArgs e)
{
//MessageBox.Show(((FrameworkElement)e.Source).Name);
//Minimize button
if ((((FrameworkElement)e.Source).Name) == "miniWindow")
{
this.WindowState = WindowState.Minimized;
//Original Design
miniWindow.Background = Brushes.Gray;
miniWindow.FontSize = 15;
}
//Close button 'X' (This works for the 'X' but not for the MenuItem)
else if ((((FrameworkElement)e.Source).Name) == "closeWindow" ||
(((FrameworkElement)e.Source).Name) == "closeWindowMenu")
{
Close();
}
}
I've tried using two different mouse and both of those had the exact same results. For the record, this same piece of code works if I was to press the 'X' to close the window.
Any reason why you are using the MouseUp event instead of the Click event?
Try using Click. In your XAML:
<MenuItem x:Name="closeWindowMenu"
Header="Close"
Click="button_Click"/>
And in your C#:
private void button_Click(object sender, RoutedEventArgs e)
{
//MessageBox.Show(((FrameworkElement)e.Source).Name);
//Minimize button
if ((((FrameworkElement)e.Source).Name) == "miniWindow")
...
}
It looks like the MouseUp event is already consumed by the control and is not bubbled up. So your handler is never triggered. If you definitely need to rely on this event then you will have to subscribe to the tunnelled equivalent: PreviewMouseUp. Other then that your code will look exactly the same.
<MenuItem x:Name="closeWindowMenu"
Header="Close"
PreviewMouseUp="button_PreviewMouseUp"/>
Edit:
You can check MenuItem source code here. It already consumes OnMouseLeftButtonUp so that's probably why your code responds to the right click but not to the left click.
I didn't know how to make the 'issue' (different behavior) more clear in the title, but I'll explain here.
In our WPF application, we're using the DataGrid control to list a number of entities. After double clicking a row, we open a new Window and in that Window, there are among other things a couple of MenuItem controls.
The problem is that when the Window opens on a position where one of the menu items is right under the mouse pointer, the menu item is actually clicked there at the mouse up of the double click.
When we use a button instead, the button click event is not fired automatically in the same situation.
We are now thinking about using buttons instead of menu items (or creating custom menus), but perhaps someone here has an explanation or solution to alter this behavior? Personally, I can't think of a case where this would be beneficial at all. Thanks in advance!
Example code is below. To see what I mean, double click the DataGrid row to open the new window and hold down the mouse button, move to the menu item and let the mouse button go (in TestWindow.xaml, exchange the MenuItem for a Button control to see the difference in behavior):
MainWindow.xaml
<Window x:Class="WpfApplication2.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">
<Window.Resources>
<Style x:Key="DataGridRowStyle"
TargetType="{x:Type DataGridRow}">
<EventSetter Event="MouseDoubleClick" Handler="DataGridRow_MouseDoubleClick" />
</Style>
</Window.Resources>
<DataGrid RowStyle="{StaticResource DataGridRowStyle}" x:Name="MyDataGrid">
<DataGrid.Columns>
<DataGridTextColumn Header="String" Binding="{Binding}" IsReadOnly="True" />
</DataGrid.Columns>
</DataGrid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
ObservableCollection<string> myCollection = new ObservableCollection<string>();
myCollection.Add("test");
MyDataGrid.ItemsSource = myCollection;
this.DataContext = this;
}
private void DataGridRow_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
TestWindow window = new TestWindow();
window.Show();
window.Activate();
}
}
TestWindow.xaml
<Window x:Class="WpfApplication2.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TestWindow" Height="300" Width="300">
<Grid>
<MenuItem Header="Test" Click="Button_Click" />
</Grid>
TestWindow.xaml.cs
public partial class TestWindow : Window
{
public TestWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
You could try modifying your DataGridRow_MouseDoubleClick handler as follows:
private void DataGridRow_MouseDoubleClick( object sender, MouseButtonEventArgs e )
{
this.Dispatcher.BeginInvoke(
( Action )delegate
{
TestWindow window = new TestWindow();
window.Show();
window.Activate();
},
System.Windows.Threading.DispatcherPriority.Background,
null
);
}
That might solve the problem by letting the outstanding events "settle" before creating the new window.