Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I do this by using an attached behaviour with 3 dependency properties; one is the command to execute, one is the parameter to pass to the command and the other is the key which will cause the command to execute. Here's the code:</p> <pre><code>public static class CreateKeyDownCommandBinding { /// &lt;summary&gt; /// Command to execute. /// &lt;/summary&gt; public static readonly DependencyProperty CommandProperty = DependencyProperty.RegisterAttached("Command", typeof(CommandModelBase), typeof(CreateKeyDownCommandBinding), new PropertyMetadata(new PropertyChangedCallback(OnCommandInvalidated))); /// &lt;summary&gt; /// Parameter to be passed to the command. /// &lt;/summary&gt; public static readonly DependencyProperty ParameterProperty = DependencyProperty.RegisterAttached("Parameter", typeof(object), typeof(CreateKeyDownCommandBinding), new PropertyMetadata(new PropertyChangedCallback(OnParameterInvalidated))); /// &lt;summary&gt; /// The key to be used as a trigger to execute the command. /// &lt;/summary&gt; public static readonly DependencyProperty KeyProperty = DependencyProperty.RegisterAttached("Key", typeof(Key), typeof(CreateKeyDownCommandBinding)); /// &lt;summary&gt; /// Get the command to execute. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public static CommandModelBase GetCommand(DependencyObject sender) { return (CommandModelBase)sender.GetValue(CommandProperty); } /// &lt;summary&gt; /// Set the command to execute. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;param name="command"&gt;&lt;/param&gt; public static void SetCommand(DependencyObject sender, CommandModelBase command) { sender.SetValue(CommandProperty, command); } /// &lt;summary&gt; /// Get the parameter to pass to the command. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public static object GetParameter(DependencyObject sender) { return sender.GetValue(ParameterProperty); } /// &lt;summary&gt; /// Set the parameter to pass to the command. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;param name="parameter"&gt;&lt;/param&gt; public static void SetParameter(DependencyObject sender, object parameter) { sender.SetValue(ParameterProperty, parameter); } /// &lt;summary&gt; /// Get the key to trigger the command. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public static Key GetKey(DependencyObject sender) { return (Key)sender.GetValue(KeyProperty); } /// &lt;summary&gt; /// Set the key which triggers the command. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;param name="key"&gt;&lt;/param&gt; public static void SetKey(DependencyObject sender, Key key) { sender.SetValue(KeyProperty, key); } /// &lt;summary&gt; /// When the command property is being set attach a listener for the /// key down event. When the command is being unset (when the /// UIElement is unloaded for instance) remove the listener. /// &lt;/summary&gt; /// &lt;param name="dependencyObject"&gt;&lt;/param&gt; /// &lt;param name="e"&gt;&lt;/param&gt; static void OnCommandInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { UIElement element = (UIElement)dependencyObject; if (e.OldValue == null &amp;&amp; e.NewValue != null) { element.AddHandler(UIElement.KeyDownEvent, new KeyEventHandler(OnKeyDown), true); } if (e.OldValue != null &amp;&amp; e.NewValue == null) { element.RemoveHandler(UIElement.KeyDownEvent, new KeyEventHandler(OnKeyDown)); } } /// &lt;summary&gt; /// When the parameter property is set update the command binding to /// include it. /// &lt;/summary&gt; /// &lt;param name="dependencyObject"&gt;&lt;/param&gt; /// &lt;param name="e"&gt;&lt;/param&gt; static void OnParameterInvalidated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) { UIElement element = (UIElement)dependencyObject; element.CommandBindings.Clear(); // Setup the binding CommandModelBase commandModel = e.NewValue as CommandModelBase; if (commandModel != null) { element.CommandBindings.Add(new CommandBinding(commandModel.Command, commandModel.OnExecute, commandModel.OnQueryEnabled)); } } /// &lt;summary&gt; /// When the trigger key is pressed on the element, check whether /// the command should execute and then execute it. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;param name="e"&gt;&lt;/param&gt; static void OnKeyDown(object sender, KeyEventArgs e) { UIElement element = sender as UIElement; Key triggerKey = (Key)element.GetValue(KeyProperty); if (e.Key != triggerKey) { return; } CommandModelBase cmdModel = (CommandModelBase)element.GetValue(CommandProperty); object parameter = element.GetValue(ParameterProperty); if (cmdModel.CanExecute(parameter)) { cmdModel.Execute(parameter); } e.Handled = true; } } </code></pre> <p>To use this from xaml you can do something like this:</p> <pre><code>&lt;TextBox framework:CreateKeyDownCommandBinding.Command="{Binding MyCommand}"&gt; &lt;framework:CreateKeyDownCommandBinding.Key&gt;Enter&lt;/framework:CreateKeyDownCommandBinding.Key&gt; &lt;/TextBox&gt; </code></pre> <p><strong>Edit:</strong> CommandModelBase is a base class I use for all commands. It's based on the CommandModel class from Dan Crevier's article on MVVM (<a href="http://blogs.msdn.com/dancre/archive/2006/09/15/dm-v-vm-part-7-encapsulating-commands.aspx" rel="noreferrer">here</a>). Here's the source for the slightly modified version I use with CreateKeyDownCommandBinding:</p> <pre><code>public abstract class CommandModelBase : ICommand { RoutedCommand routedCommand_; /// &lt;summary&gt; /// Expose a command that can be bound to from XAML. /// &lt;/summary&gt; public RoutedCommand Command { get { return routedCommand_; } } /// &lt;summary&gt; /// Initialise the command. /// &lt;/summary&gt; public CommandModelBase() { routedCommand_ = new RoutedCommand(); } /// &lt;summary&gt; /// Default implementation always allows the command to execute. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;param name="e"&gt;&lt;/param&gt; public void OnQueryEnabled(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = CanExecute(e.Parameter); e.Handled = true; } /// &lt;summary&gt; /// Subclasses must provide the execution logic. /// &lt;/summary&gt; /// &lt;param name="sender"&gt;&lt;/param&gt; /// &lt;param name="e"&gt;&lt;/param&gt; public void OnExecute(object sender, ExecutedRoutedEventArgs e) { Execute(e.Parameter); } #region ICommand Members public virtual bool CanExecute(object parameter) { return true; } public event EventHandler CanExecuteChanged; public abstract void Execute(object parameter); #endregion } </code></pre> <p>Comments and suggestions for improvements would be very welcome.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload