应用场景

我现在做一个系统登录功能,要求在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中支持回车命令的更多相关文章

  1. 基于WPF系统框架设计(5)-Ribbon整合Avalondock 2.0实现多文档界面设计(二)

    AvalonDock 是一个.NET库,用于在停靠模式布局(docking)中排列一系列WPF/WinForm控件.最新发布的版本原生支持MVVM框架.Aero Snap特效并具有更好的性能. Ava ...

  2. 基于WPF系统框架设计(1)-为什么要仿Office2010 Ribbon?

    为什么系统框架设计使用Ribbon导航模式? 这得从Office软件的演变说起.微软为什么最后选择使用Ribbon,也许就是很多系统设计要使用Ribbon做功能导航的原因. 你是否还记得曾经使用过的M ...

  3. 基于WPF系统框架设计(8)-PasswordBox传值到ViewMode

    应用场景 我要做一个系统登录功能,需要传用户名和密码到ViewModel中,可是PasswordBox传值到ViewModel中好像跟TextBox等控件不一样.这里需要用到附加属性. 附加属性:一个 ...

  4. 基于WPF系统框架设计(4)-Ribbon整合Avalondock 2.0实现多文档界面设计(一)

    前些时间研究了WPF的一些框架,感觉基于Prism框架的MVVM模式对系统的UI与逻辑分离很好,所以就按照之前Winform的框架设计,用WPF做了一套,感觉比Winform要强很多. MVVM模式和 ...

  5. 基于WPF系统框架设计(3)-Fluent Ribbon界面布局

    一个系统框架除了功能菜单导航,有系统内容显示区域,系统状态栏. Silver: Blue: Black: 系统界面设计,就不进行技术细节介绍了,主题以框架设计为主,Xaml源码参考: <Flue ...

  6. 基于WPF系统框架设计(9)-多值绑定之IMultiValueConverter

    应用场景 我想把View层的一个布局控件和功能按钮传到ViewModel层,达到动态变更布局,同时灵活获取功能按钮的属性,让View和ViewModel完全分离,而不受View层影响. 最后我想到使用 ...

  7. 基于WPF系统框架设计(6)-整合MVVM框架(Prism)

    应用场景 我们基础的框架已经搭建起来了,现在整合MVVM框架Prism,在ViewModel做一些逻辑处理,真正把界面设计分离出来. 这样方便我们系统开发分工合作,同时提高系统可维护性和灵活性. 具体 ...

  8. 基于WPF系统框架设计(2)-Fluent Ribbon之HelloWorld

    Fluent/Ribbon是微软在其最新桌面操作系统Windows 7中使用的图形用户界面. Windows平台的进化,伴随着系统图形界面的重新设计.从Windows XP到Windows Vista ...

  9. 基于WPF系统框架设计(10)-分页控件设计

    背景 最近要求项目组成员开发一个通用的分页组件,要求是这个组件简单易用,通用性,兼容现有框架MVVM模式,可是最后给我提交的成果勉强能够用,却欠少灵活性和框架兼容性. 设计的基本思想 传入数据源,总页 ...

随机推荐

  1. day23 Model 操作,Form 验证以及序列化操作

    Model 操作 1创建数据库表 定制表名:       普通索引:             创建两个普通索引,这样就会生成两个索引文件   联合索引:           为了只生成一个索引文件,才 ...

  2. python 二——函数、装饰器、生成器、面向对象编程(初级)

    本节内容 1.函数 2.装饰器 3.生成器 4.类 一.函数 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 函数式 ...

  3. 8、HTML DOM总结

    1.HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model):HTML DOM 模型被构造为对象的树. 2.DOM 方法 < ...

  4. IOS笔记048-数据存储

      IOS数据存储的几种方式         XML属性列表(plist)         归档 Preference(偏好设置)          NSKeyedArchiver归档(NSCodin ...

  5. LeetCode118 杨辉三角 Python

    给定一个非负整数 numRows,生成杨辉三角的前 numRows 行. 示例:输入: 5 输出: [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] cl ...

  6. Unity 移动方式总结

    1. 简介 在Unity3D中,有多种方式可以改变物体的坐标,实现移动的目的,其本质是每帧修改物体的position. 2. 通过Transform组件移动物体 Transform 组件用于描述物体在 ...

  7. ABP 未能加载文件或程序集“System.ComponentModel.Annota, Version=4.2.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。

    切换System.ComponentModel.Annotations版本到4.4.1  重新编译即可

  8. 将数据缓存到sessionStorage中

    //获取侧边栏 if (sessionStorage.getItem(`${env}${empId}leftMenu`)) { const leftMenu = JSON.parse(sessionS ...

  9. 抓取js动态生成数据

    最近在抓数据,一般的网页数据抓取相对容易一些,今天在抓电视猫的节目单,发现有些数据时抓取不到的,Java端得到的HTML文件里面没有某一段代码,查了很多资料,发现说是js动态生成的数据,无法直接抓取, ...

  10. [bzoj4259][bzoj4503] 残缺的字符串 [FFT]

    题面 传送门 bzoj上的这两题是一样的...... 正文 我看到这道题,第一想法是跑魔改过的KMP,然后很快发现不可行 于是想换个角度思考 其实,本题最大的问题就在于通配符的存在:它可以匹配任意一个 ...