I currently have a listbox in wpf c# and added some keybindings to the keydown event handler of my main window. It's event handlers for the spacebar and the up/down keys. However, when my listbox has focus, these bindings are not initiated. How can I disable these default keybindings (without entering a e.handle = true so the entire keystroke is disabled) for this control and run my own code?
The default keybindings do not use events directly but commands. What you can do is to define commands and attach events to them.
<Window.Resources>
<CommandBinding x:Key="NewBinding" Command="ApplicationCommands.New"
Executed="NewCommand" CanExecute="CanExecuteNew">
</CommandBinding>
</Window.Resources>
<ListBox.CommandBindings>
<StaticResource ResourceKey="NewBinding"></StaticResource>
</ListBox.CommandBindings>
To override default keybindings the syntax is :
<Window.InputBindings>
<KeyBinding Key="" Modifiers="" Command="" />
</Window.InputBindings>
If you are new to this try to get some overview WPF Commanding Overview and Advanced WPF you are going to have hard time to do so with events.
Related
I am making the close, maximize and minimize buttons in WPF C#. I tried two different methods and both seemed to work with me but I just want to know which approach in general is considered a better practice for this kind of implementation.
Method one:
in XAML:
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_CanExecute_1" Executed="CommandBinding_Executed_1" />
<CommandBinding ... />
<CommandBinding ... />
</Window.CommandBindings>
<Button Command="{x:Static SystemCommands.CloseWindowCommand}" Content ="close"/>
<Button ... />
<Button .../>
in C#:
private void CommandBinding_Executed_1(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.CloseWindow(this);
}
...
Method two:
in XAML:
<Button Content="X" Click="CloseButton_Click" />
<Button .../>
<Button ... />
in C#:
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
Close();
}
...
Since the close, maximize and minimize buttons are typically part of a control, or a template of a control, you could handle the Click event of the buttons directly. There is no need nor reason to introduce any command bindings just to be able to handle the click of a Button internally in a control.
You could either hook up the event handlers in XAML or, if the buttons are defined in a ControlTemplate of a custom control, you could override the OnApplyTemplate() method of the control and hook up the event handlers programmatically as suggested here: https://blog.magnusmontin.net/2013/03/16/how-to-create-a-custom-window-in-wpf/.
Button click handler is simple and fast (to implement). If you are sure you are going to use just this button to close your window - click handler is good enough. If however there is possibility you are going to need more than one place to close the window (for example - you are going to use "close" menu option) - then it's better to not spread the same logic over multiple places and use a command, because command has all handling logic in one place (CommandBinding_Executed_1 in your case). Also, command has CanExecute logic so you will be able to automatically disable your close button (and all other "close" controls) in case window cannot be closed right now (with click handler you will have to code this logic yourself). Also, with command you can close your window from any control down the tree, even if that control has no reference to your window at all. This applies to "command vs click handler" in general, not specifically to the case with closing window where some of the above might seem a bit contrieved.
I am trying to write a XAML control for a Piano Keyboard in WPF which responds to NoteOn and NoteOff MIDI events from an external MIDI keyboard. I am using Tom Lokovic's midi-dot-net to raise NoteOn and NoteOff events triggered by the hardware but I need a way to get these events to raise the NoteOn and NoteOff events of my XAML Key class (derived from the WPF Button). The colour of a key should change when it is on and the event should be subscribable to so that a user of the Piano Keyboard control can play a sound the key is pressed.
I could do this by passing every Midi.InputDevice to every single key on the keyboard so that each one can subscribe to the NoteOn and NoteOff events of every InputDevice then, in turn raise their own NoteOn and NoteOff events but the problem with this is that the PianoKeyboard control (an ItemsControl which holds Keys) and its nested Key controls all become tightly coupled to the implementation of midi-dot-net. If I have to do this I will, but it seemed like there should be a better way of doing this in WPF moving the dependency on midi-dot-net higher up in the call stack.
I have too much code to paste in its entirety here and still be readable so here's a sample of one of the DataTemplates I'm using as my PianoKeyboard's ItemTemplate.
<DataTemplate x:Key="naturalKeyTemplate">
<!--NOTE: Background and Foreground Color assignment and changing is accounted for in the style.-->
<local:Key Grid.Column="{Binding Converter={StaticResource keyToColumnNumberConverter}}"
Grid.ColumnSpan="{Binding Converter={StaticResource keyToColumnSpanConverter}}"
Grid.RowSpan="2"
Style="{StaticResource naturalKeyStyle}"
Note="{Binding Note}"
IsHighlighted="{Binding IsHighlighted}">
<!--TODO: Find a way of raising the Key's NoteOn and NoteOff events from here.-->
</local:Key>
</DataTemplate>
Essentially what I'm asking is: given an input device is not supported to trigger a WPF button with the button's built in behaviour (e.g. a mouse click), how does one get it to trigger the button without coupling it to a derived class of the button?
You could raise the Click event programmatically:
button1.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
I think this can help you to call specific Metod based on event called.
<local:Key>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Mouse.PreviewMouseDown">
<ei:CallMethodAction MethodName="NoteOn"
TargetObject="{Binding}" />
</i:EventTrigger>
<i:EventTrigger EventName="Mouse.PreviewMouseUp">
<ei:CallMethodAction MethodName="NoteOff"
TargetObject="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</local:Key>
You will need to add xmlns extensions:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
I would have done a MIDI listenner service singleton that listen to all midi events, which update a keyboard state repository, which expose a viewmodel binded to your keyboard control...but i do not really see your programm structure, so it's not easy to say.
binding the midi event in your xaml to the wrapper midi.net does not seems to be the LOB way, because you link the gui with midi.net...
by the way, On/Off, is not enough, you need "pressed" as key is pressed state??
I am new to WPF and am going through the examples of Professional WPF in .net 4.5. In the commands chapter, there is an example where multiple controls can send the same command. I am using a Button, CheckBox and MenuItem to trigger the New command.
The issue I am facing is that if MenuItem is pressed for the first time, the source shows correctly. However, after clicking the Button or CheckBox, then clicking MenuItem shows me the source of the last control Button or CheckBox, whichever was pressed. I couldn't find what was wrong with my code or why is this behavior shown by MenuItem in WPF.
Below is the code.
<Window x:Class="WpfApplication1.CommandSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="CommandSample" Height="300" Width="300">
<Window.CommandBindings>
<CommandBinding Command="New" Executed="CommandBinding_Executed" />
</Window.CommandBindings>
<StackPanel>
<Button Command="New" MaxWidth="80" MaxHeight="30" Content="{x:Static ApplicationCommands.New}" />
<Menu MaxHeight="30" VerticalAlignment="Top">
<MenuItem Header="File">
<MenuItem Command="New"></MenuItem>
</MenuItem>
</Menu>
<CheckBox Command="New"></CheckBox>
</StackPanel>
</Window>
namespace WpfApplication1 {
public partial class CommandSample: Window {
public CommandSample() {
InitializeComponent();
}
private void CommandBinding_Executed(object sender,ExecutedRoutedEventArgs e)
{
MessageBox.Show("New Command launched by " + e.Source);
}
}
}
Yes this is correct (or at least that's how it's designed). Routed commands start routing based on the CommandTarget you specify. If one isn't specified typically the object raising the event uses itself as the starting point (so the MenuItem in this case). So the routing starts with the MenuItem in this case as you might expect. Nothing handles it there so the CommandManager goes up the parent chain. When it hits an element that is a FocusScope (like the Menu), it checks the FocusedElement of the "parent" FocusScope (e.g. the FocusScope of the parent of the Menu which in this case is the Window). If there is a FocusedElement (which there will be one once you have focused an element in the window's focus scope such as your button, checkbox, a textbox that you might put in that stackpanel, etc.) then the CommandManager starts routing the event from that element. When it does that it creates a new ExecutedRoutedEventArgs where the OriginalSource is that starting element (so the button, checkbox, textbox) and then continues routing up the tree.
So when you first ran the app, the FocusedElement of the Window (that's the root focus scope in your example) is null so there is no re-routing needed so the CommandManager just kept going up the parent chain past the Menu and that is why MenuItem appeared as the Source & OriginalSource. When you clicked on the Button you gave that keyboard focus and as part of it also became the logically focused element of its focus scope (i.e. the FocusedElement of its containing FocusScope). So when the MenuItem was subsequently clicked and the CommandManager ultimately reached the Menu, it then re-routed over to the Button (or whatever you focused in the window's focusscope) and started routing up from there. I say this is expected because with routed command you want the routing to go through the logically focused element so that for example, the Cut command of a menu item would trigger a cut of the TextBox in the Window that had focus.
I have a main window with some keybindings like this:
<Window.InputBindings>
<KeyBinding Command="{Binding RotateCommand}"
CommandParameter="left"
Key="L">
</KeyBinding>
<KeyBinding Command="{Binding RotateCommand}"
CommandParameter="right"
Key="R" />
</Window.InputBindings>
The problem is that I am unable to type this letters in any textboxes in that window, keys L and R just call commands.
Is there any way to disable KeyBindings inside of some controls? (Maybe when some controls have a focus).
I search through the internet and find this, but I can't get access to CanExecute routed event because I'm using mvvm model for command bindings.
I am able to bind buttons and menu items with ICommand and close the windows.
It is exactly as described in the tutorial WPF Apps With The Model-View-ViewModel Design Pattern - via the Command property accessible in XAML.
But it is not described or implemented in the tutorial how to close by pressing the standard 'Close' icon on the top-right of the window. I need to perform some clean up in my application.
My question is how to bind a Command to the close event, so that it is executed when the user presses the close icon (not buttons or menu items - I know how to manage such cases).
How should this be handled to avoid violating the MVVM approach?
Thanks!
The MVVM Light Toolkit contains a behaviour called EventToCommand, which gives you an easy way to bind a command to an event.
The following XAML snippet shows an example of how to get a command called "CloseCommand" to execute when the window's Closed event is raised:
<Window x:Class="EventToCommand.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
Title="MainWindow" Height="300" Width="500">
<!-- Make sure to put this tag directly inside the Window,
and not inside a child element, since it is the Windows that has the Closed event -->
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closed">
<cmd:EventToCommand Command="{Binding CloseCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<!-- Windows contents -->
</Window>
To get access to the EventToCommand behaviour, you need to download MVVM Light Toolkit from the project downloads page, and then reference the following DLLs:
GalaSoft.MvvmLight.dll
GalaSoft.MvvmLight.Extras.dll
System.Windows.Interactivity.dll
That is all that is needed.
Further instructions of how to get started with the toolkit can be found here.
I would bind a Command to the Application's Exit event
I like using the AttachedCommand behavior found here for binding Commands to Events, although I know you can also accomplish the same thing using Blend's Interaction Triggers.