應用場景
我現在做一個系統登錄功能,要求在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();//全選文本 } }
測試
運行程序后,輸入用戶密碼,顯示如圖:


