应用场景

我现在做一个系统登录功能,要求在PasswordBox上输完密码后回车,能够响应Enter事件,并执行ViewModel中对应的方法。如果登录成功则隐藏当前窗口显示主窗体,登录失败则焦点返回到用户名TextBox中,并全选文字,方便用户再重新输入。

这个在我们制造业自动化流程控制中,做防呆功能是很明显的,因为没有人为去参与。

如果像Winform一样的开发模式,就相对很简单了,现在是要在ViewModel,对一个初学者来说就相对地困难多了,那怎么办呢?

设计思想

自定义一个Command,支持多参数对象数组,把控件,事件传到ViewModel中。

实现步骤

  1. 自定义命令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();//全选文本
}
}

测试

运行程序后,输入用户密码,显示如图:

基于WPF系统框架设计(7)-TextBox/PasswordBox在ViewModel中支持回车命令-LMLPHP

基于WPF系统框架设计(7)-TextBox/PasswordBox在ViewModel中支持回车命令-LMLPHP

04-18 03:20