应用场景
我现在做一个系统登录功能,要求在PasswordBox上输完密码后回车,能够响应Enter事件,并执行ViewModel中对应的方法。如果登录成功则隐藏当前窗口显示主窗体,登录失败则焦点返回到用户名TextBox中,并全选文字,方便用户再重新输入。
这个在我们制造业自动化流程控制中,做防呆功能是很明显的,因为没有人为去参与。
如果像Winform一样的开发模式,就相对很简单了,现在是要在ViewModel,对一个初学者来说就相对地困难多了,那怎么办呢?
设计思想
自定义一个Command,支持多参数对象数组,把控件,事件传到ViewModel中。
实现步骤
- 自定义命令InteractiveCommand类,继承TriggerAction<DependencyObject>
// ----------------------------------------------------------------------- // <copyright file="InteractiveCommand.cs" company=""> // TODO: Update copyright text. // </copyright> // ----------------------------------------------------------------------- namespace TLAgent.SecurityManager.WPF { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; using System.Reflection; /// <summary> /// TODO: Update summary. /// </summary> public class InteractiveCommand : TriggerAction<DependencyObject> { protected override void Invoke(object parameter) { if (base.AssociatedObject != null) { ICommand command = this.ResolveCommand(); object[] tempObj = { parameter, CommandParameter }; if ((command != null) && command.CanExecute(tempObj)) { command.Execute(tempObj); } } } public object CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register ("CommandParameter", typeof(object), typeof(InteractiveCommand), new PropertyMetadata(null, OnCommandParameterChanged)); private static void OnCommandParameterChanged (DependencyObject sender, DependencyPropertyChangedEventArgs e) { InteractiveCommand ic = sender as InteractiveCommand; if (ic != null) { ic.SynchronizeElementState(); } } private void SynchronizeElementState() { ICommand command = Command; if (command != null) { FrameworkElement associatedObject = AssociatedObject as FrameworkElement; if (associatedObject != null) { associatedObject.IsEnabled = command.CanExecute(CommandParameter); } } } private ICommand ResolveCommand() { ICommand command = null; if (this.Command != null) { return this.Command; } if (base.AssociatedObject != null) { foreach (PropertyInfo info in base.AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if (typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, this.CommandName, StringComparison.Ordinal)) { command = (ICommand)info.GetValue(base.AssociatedObject, null); } } } return command; } private string commandName; public string CommandName { get { base.ReadPreamble(); return this.commandName; } set { if (this.CommandName != value) { base.WritePreamble(); this.commandName = value; base.WritePostscript(); } } } #region Command public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null)); #endregion } }
2. 在XAML中做绑定,把EventName定为”KeyDown“,请参考如下代码:
<PasswordBox x:Name="txtPassword" Height="23" Helper:PasswordBoxHelper.Attach="True" Helper:PasswordBoxHelper.Password="{Binding Path=AuthUser.Password,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="101,92,0,0" VerticalAlignment="Top" Width="178" TabIndex="2"> <i:Interaction.Triggers> <i:EventTrigger EventName="KeyDown"> <Helper:InteractiveCommand Command="{Binding EnterLoginCommand}" CommandName="EnterLoginCommand" CommandParameter="{Binding ElementName=txtUserName}"/> </i:EventTrigger> </i:Interaction.Triggers> </PasswordBox>
3. 后台的Command声明为DelegateCommand<object[]><object[]><object[]><object[]> _CommandWithEventArgs,并实例化,同时绑定一个带参数object[]的用户验证方法:
public ICommand EnterLoginCommand { get { return _CommandWithEventArgs ?? (_CommandWithEventArgs = new DelegateCommand<object[]>(CheckUser)); } }
绑定的方法为CheckUser,如下
private void CheckUser(object[] objs) { KeyEventArgs e = objs[0] as KeyEventArgs; if (e.Key == Key.Enter) { object obj = objs[1]; VerifyUser(obj); } } private void VerifyUser(object objParam) { if (AuthUser.UserName != null && AuthUser.Password != null) { if (AuthUser.UserName.ToUpper().Equals("AGAN") && AuthUser.Password.Equals("123")) { IsVisibility = Visibility.Hidden; SplashScreen splashScreen = new SplashScreen("Images/SplashScreen.JPG"); splashScreen.Show(true); MainWindow window = new MainWindow(); window.ShowDialog(); } else { MessageBox.Show(@"用户名或密码错误!"); TextBox txtUserName = (TextBox)objParam; txtUserName.Focus(); txtUserName.SelectAll(); } } else { MessageBox.Show(@"用户名或密码不能为空!"); TextBox txtUserName = (TextBox)objParam;//转换为TextBox,即为View层的txtUserName控件 txtUserName.Focus();//获取焦点 txtUserName.SelectAll();//全选文本 } }
测试
运行程序后,输入用户密码,显示如图: