Today, I had to build a simple login form using Silverlight 3 and Prism in a MVVM application. One requirement that I always put on any login form is that the user can hit the enter key to submit her credentials for validation. This is my solution:
KeyUpBehavior.cs
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Practices.Composite.Presentation.Commands;
namespace Infrastructure.Commands.PasswordCommands
{
public class KeyUpBehavior : CommandBehaviorBase<Control>
{
public KeyUpBehavior(Control element)
: base(element)
{
element.KeyUp += new KeyEventHandler(element_KeyUp);
}
void element_KeyUp(object sender, KeyEventArgs e)
{
//only execute command if the user pressed the enter key
if (e.Key == Key.Enter)
base.ExecuteCommand();
}
}
}
KeyUp.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Infrastructure.Commands.PasswordCommands
{
public class KeyUp
{
#region Command attached property
public static ICommand GetCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(CommandProperty);
}
public static void SetCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(CommandProperty, value);
}
// Using a DependencyProperty as the backing store for Command. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(KeyUp), new PropertyMetadata(OnSetCommandCallback));
private static void OnSetCommandCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
Control element = dependencyObject as Control;
if (element != null)
{
KeyUpBehavior behavior = GetOrCreateBehavior(element);
behavior.Command = e.NewValue as ICommand;
}
}
private static KeyUpBehavior GetOrCreateBehavior(Control element)
{
KeyUpBehavior behavior = element.GetValue(KeyUpBehaviorProperty) as KeyUpBehavior;
if (behavior == null)
{
behavior = new KeyUpBehavior(element);
element.SetValue(KeyUpBehaviorProperty, behavior);
}
return behavior;
}
#endregion
#region KeyUpBehavior attached property
public static KeyUpBehavior GetKeyUpBehavior(DependencyObject obj)
{
return (KeyUpBehavior)obj.GetValue(KeyUpBehaviorProperty);
}
public static void SetKeyUpBehavior(DependencyObject obj, KeyUpBehavior value)
{
obj.SetValue(KeyUpBehaviorProperty, value);
}
public static readonly DependencyProperty KeyUpBehaviorProperty =
DependencyProperty.RegisterAttached("KeyUpBehavior", typeof(KeyUpBehavior), typeof(KeyUp), null);
#endregion
#region CommandParameter attached property
public static object GetCommandParameter(DependencyObject obj)
{
return (object)obj.GetValue(CommandParameterProperty);
}
public static void SetCommandParameter(DependencyObject obj, object value)
{
obj.SetValue(CommandParameterProperty, value);
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.RegisterAttached("CommandParameter", typeof(object), typeof(KeyUp), new PropertyMetadata(OnSetCommandParameterCallback));
private static void OnSetCommandParameterCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
Control element = dependencyObject as Control;
if (element != null)
{
KeyUpBehavior behavior = GetOrCreateBehavior(element);
behavior.CommandParameter = e.NewValue;
}
}
#endregion
}
}
View
<PasswordBox Grid.Row="2"
Grid.Column="2"
customCommands:KeyUp.Command="{Binding KeyUp_Command}"
customCommands:KeyUp.CommandParameter="{Binding Password, ElementName=txtPassword}"
Password="{Binding Path=User.Password, Mode=TwoWay}"
x:Name="txtPassword" />
ViewModel
public DelegateCommand<object> KeyUp_Command { get; set; }
public void KeyUpCommand_Handler(object commandParameter)
{
//do authentication, commandParameter is the value stored in PasswordBox.Password.
}
ViewModel constructor
KeyUp_Command = new DelegateCommand<object>(KeyUpCommand_Handler);
Advertisement
Tried this and did not get it to work. The event is set on a textbox, I can see that in the debugger. But it is never fired. So I just to see if a KeyUp event on the textbox actually works , I added the KeyUp=”myEvent” and added MyEvent in the code behind, and even that event does not get triggered. So your sample is probably fine, just in my case (SL3) the keyup does not work at all.
Any idea why?
Tnx
Ben
Comment by Ben — June 29, 2010 @ 1:35 pm
I forgot to put the code to set the ViewModel as the View’s DataContext. In the View’s codebehind, instantiate a new ViewModel. Then, set
this.DataContext = ViewModel;
Check out MVVM-Light on codeplex for a much cleaner way to command events back to the view model. Laurent uses Expression interactions to convert the event to a command.
http://mvvmlight.codeplex.com/
Comment by bobbsmooth — June 30, 2010 @ 2:31 pm