Data validation is a key part in WPF.
Validation is used to alert the user that the data he entered is illegal.
In this post we will see how to Validate user input using MVVM binding.
I have created 2 different templates for input validation :
Click WPFInputValidation Link To Download full source.
Example 1 :
To impelment validation we need to use IDataErrorInfo interface.
IDataErrorInfo  interface provides the functionality to offer custom error information that a user  interface can bind to.
It has 2 Properties :
- Error : Gets an error message indicating what is wrong with this object.
- string this[string columnName] Indexer : it will return the error message for the property. The default is an empty string ("")

Let's go through step by step to understand validation with mvvm binding and styling the validation template.
Step 1 :  First change ErrorToolTip style by customizing the Template.

  1.  
  1.  
  1. <ControlTemplate x:Key="ErrorToolTipTemplate_1">
  2. <ControlTemplate.Resources>
  3. <Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
  4. <Setter Property="HorizontalAlignment" Value="Center" />
  5. <Setter Property="VerticalAlignment" Value="Center" />
  6. <Setter Property="FontWeight" Value="Bold" />
  7. <Setter Property="Foreground" Value="White" />
  8. <Setter Property="Margin" Value="10 0 10 0" />
  9. </Style>
  10. </ControlTemplate.Resources>
  11. <DockPanel LastChildFill="true">
  12. <Border Height="Auto"
  13. Margin="5,0,0,0"
  14. Background="#DC000C"
  15. CornerRadius="3"
  16. DockPanel.Dock="right">
  17. <TextBlock Style="{StaticResource textblockErrorTooltip}"
  18. Text="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
  19. </Border>
  20. <AdornedElementPlaceholder Name="customAdorner">
  21. <Border BorderBrush="#DC000C" BorderThickness="1.3" />
  22. </AdornedElementPlaceholder>
  23. </DockPanel>
  24. </ControlTemplate>
  1.  
  1.  

As shown in above source, created ControlTemplate and changed the error tooltip style by AddingBorder control in DockPanel, within Border TextBlock placed with Text property binded to the error message set to the property from viewmodel.
changed Backgroud of the border to Red so it will display error message surround with  border fill with red color. This will dispaly error on right side of the TextBox control. like :

ErrorTemplate uses adorner layer. which is drawing layer, using adorner layer you can add visual appearance to indicate an error without replacing controltemplate.
AdornedElementPlaceholder is part of the Validation feature of data binding. it specify where a decorated control is placed relative to other elements  in the ControlTemplate.
Step 2 : Create TextBox style and set Validation ErrorTemplate.

  1. <Style TargetType="TextBox">
  2. <Setter Property="HorizontalAlignment" Value="Left" />
  3. <Setter Property="VerticalAlignment" Value="Top" />
  4. <Setter Property="Width" Value="150" />
  5. <Setter Property="Height" Value="30" />
  6. <Setter Property="Validation.ErrorTemplate"
  7. Value="{DynamicResource ErrorToolTipTemplate_1}" />
  8. <Style.Triggers>
  9. <Trigger Property="Validation.HasError" Value="true">
  10. <Setter Property="ToolTip"
  11. Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
  12. </Trigger>
  13. </Style.Triggers>
  14. </Style>
  1.  

Created style of TargetType=TextBox, and Validation.ErrorTemplate is set to previously created template (DynamicResource ErrorToolTipTemplate)
you have to set Resource using DynamicResource, if your temaplate/style is available at global place (App.xaml)
if your control style and template is created in page itself then set resource using StaticResourcekeyword.
Step 3 : Create ViewModel class, that contains Properties to Bind into view.

  1. public class InputValidationViewModel : ViewModelBase
  2. {
  3. public InputValidationViewModel()
  4. {
  5. }
  6. private string employeeName;
  7. public string EmployeeName
  8. {
  9. get { return employeeName; }
  10. set { employeeName = value; RaisePropertyChanged("EmployeeName"); }
  11. }
  12. private string email;
  13. public string Email
  14. {
  15. get { return email; }
  16. set {email = value; RaisePropertyChanged("Email"); }
  17. }
  18. private long phoneNumber;
  19. public long PhoneNumber
  20. {
  21. get { return phoneNumber; }
  22. set { phoneNumber = value; RaisePropertyChanged("PhoneNumber"); }
  23. }
  24. private bool IsValidEmailAddress
  25. {
  26. get { return emailRegex.IsMatch(Email); }
  27. }
  28. }
  1.  
  1.  

as shown in above code, ViewModel created and added some propeties that need to bind in UserControl.
Step 4 : Implement IDataErrorInfo Interface

  1.  
  1.  
  1. public class InputValidationViewModel : ViewModelBase, IDataErrorInfo
  2. {
  3. private Regex emailRegex = new Regex(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$");
  4. public InputValidationViewModel()
  5. {
  6. } private string error = string.Empty;
  7. public string Error
  8. {
  9. get { return error; }
  10. }
  11. public string this[string columnName]
  12. {
  13. get
  14. {
  15. error = string.Empty;
  16. if (columnName == "EmployeeName" && string.IsNullOrWhiteSpace(EmployeeName))
  17. {
  18. error = "Employee name is required!";
  19. }
  20. else if (columnName == "PhoneNumber" && PhoneNumber == 0)
  21. {
  22. error = "Phone number is required!";
  23. }
  24. else if (columnName == "PhoneNumber" && PhoneNumber.ToString().Length > 10)
  25. {
  26. error = "Phone number must have less than or equal to 10 digits!";
  27. }
  28. else if (columnName == "Email" && string.IsNullOrWhiteSpace(Email))
  29. {
  30. error = "Email address is required!";
  31. }
  32. else if (columnName == "Email" && !IsValidEmailAddress)
  33. {
  34. error = "Please enter valid email address!";
  35. }
  36. return error;
  37.  
  38. } }
  39. }

IDataErrorInfo has Error property which returns the validation error that does not match the codition.
in above code, i set the error for each propeties by checking the codition, it coditiion is false then set the error for that property.
For valid email validation, created Regex expression to check entered email address is valid ro not.
This error appear on right side of the control that has property binded.
Step 5 : Last, Add TextBox cotrol in View

  1.  
  1.  
  1. <TextBox Grid.Row="1"
  2. Grid.Column="1"
  3. Text="{Binding EmployeeName,
  4. Mode=TwoWay,
  5. UpdateSourceTrigger=PropertyChanged,
  6. ValidatesOnDataErrors=True}" />
  1.  
  1.  

Here EmployeeName proeprty is binded to TextBox control, you have to set ValidatesOnDataErrors=True to throw data error ( entered data is valida or not.)
Mode=TwoWay will allow user to change property from UI as well update UI from ViewModel property.
UpdateSourceTrigger=PropertyChanged will notify changes  is updated as soon as the property changes.
If UpdateSourceTrigger is not set, then TextBox was not immediately sent back to the source. Instead, the source was updated only after focus was lost on the TextBox.
This behavior is controlled by a property on the binding called UpdateSourceTrigger.
Example 2 :
In this example, only ControlTemplate is chaned, other things like : ViewModels Property, Controls are same.

As shown in above image, tooltip style is changed, ! mark with red circle surrounded image is added on the errortemplate.
small triangle added on template, to show top right corner of the control if any data error exists.
below are the  template change compare to previous example template :

  1.  
  1. <Border x:Name="ValidationErrorElement"
  2. BorderBrush="#FFDB000C"
  3. BorderThickness="1.2"
  4. CornerRadius="1"
  5. ToolTip="{Binding ElementName=customAdorner,
  6. Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
  7. <Grid Width="12"
  8. Height="12"
  9. Margin="1,-4,-4,0"
  10. HorizontalAlignment="Right"
  11. VerticalAlignment="Top"
  12. Background="Transparent">
  13. <Path Margin="1,3,0,0"
  14. Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z"
  15. Fill="#FFDC000C" />
  16. <Path Margin="1,3,0,0"
  17. Data="M 0,0 L2,0 L 8,6 L8,8"
  18. Fill="#ffffff" />
  19. </Grid>
  20. </Border>
  21. <Border Grid.Column="0"
  22. Width="15"
  23. Height="15"
  24. Margin="0 0 3 0"
  25. HorizontalAlignment="Right"
  26. VerticalAlignment="Center"
  27. Background="Red"
  28. CornerRadius="10"
  29. ToolTip="{Binding ElementName=customAdorner,
  30. Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
  31. <TextBlock HorizontalAlignment="center"
  32. VerticalAlignment="center"
  33. FontWeight="Bold"
  34. Foreground="white"
  35. Text="!" />
  36. </Border>
  1.  
  1.  
  1.  

as shown in above code,
In First border, 2 shapes is created using path, this will create Triangle shape to disply on top right corner of the control.
To know more about how to draw shpaes using Path, Please refer Shapes & Drawing in WPF This Link
it will help you to create your custom shapes based on your requirement.
Second border will create red cirlce (by setting CornerRadius proeprty) with ! text wihin cirlce area.
it will display right side of the cotrol, if any data error is there for property.
Conclusion
This way you can create you custom error template for input controls.
Dwonload link

WPF Input Validation Using MVVM的更多相关文章

  1. 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1

    原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator-更新至Prism7.1 事件聚合器EventAggregator [7.1updated]除了app部分,没 ...

  2. WPF学习08:MVVM 预备知识之COMMAND

    WPF内建的COMMAND是GOF 提出的23种设计模式中,命令模式的实现. 本文是WPF学习07:MVVM 预备知识之数据绑定的后续,将说明实现COMMAND的三个重点:ICommand  Comm ...

  3. 从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator?

    原文:从PRISM开始学WPF(七)MVVM(三)事件聚合器EventAggregator? 从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WP ...

  4. 在 WPF 程序中使用 MVVM 模式

    MVVM 模式是一个很久之前的技术了,最近因为一个项目的原因,需要使用 WPF 技术,所以,重新翻出来从前的一段程序,重温一下当年的技术. MVVM 模式 MVVM 实际上涉及三个部分,Model, ...

  5. (ZZ)WPF经典编程模式-MVVM示例讲解

    http://www.cnblogs.com/xjxz/archive/2012/11/14/WPF.html 本篇从两个方面来讨论MVVM模式: MVVM理论知识 MVVM示例讲解 一,MVVM理论 ...

  6. 从PRISM开始学WPF(六)MVVM(二)Command?

    从PRISM开始学WPF(一)WPF? 从PRISM开始学WPF(二)Prism? 从PRISM开始学WPF(三)Prism-Region? 从PRISM开始学WPF(四)Prism-Module? ...

  7. 从PRISM开始学WPF(六)MVVM(二)Command-更新至Prism7.1

    命令绑定(Command) [7.1updated]这一节除了基础app部分,并没有什么变化 什么是Command? 先看下微软官方的说明: Commanding is an input mechan ...

  8. WPF 从属性赋值到MVVM模式详解

    示例源码 这两天学习了一下MVVM模式,和大家分享一下,也作为自己的学习笔记.这里不定义MVVM的概念,不用苍白的文字说它的好处,而是从简单的赋值讲起,一步步建立一个MVVM模式的Simple.通过前 ...

  9. WPF学习笔记:MVVM模式下,ViewModel如何关闭View?

    原文:http://blog.csdn.net/leftfist/article/details/32349731 矫枉过正,从一个极端走向另一个极端.MVVM模式,View只负责呈现,虽然也有后台代 ...

随机推荐

  1. android monitor 汉化

    作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E-mail: 313134555 @qq.com === == ============= = ...

  2. Scratch儿童项目式编程—捉迷藏游戏 Scratch children project programming - hide-and-seek game

    Scratch儿童项目式编程—捉迷藏游戏 Scratch children project programming - hide-and-seek game 作者:韩梦飞沙 Author:han_me ...

  3. AD软件原理图封装过程(即由原理图转换到PCB)

    第一步:先画出你所要的原理图 第二步:点击菜单栏的工具→封装管理器,进去封装管理器页面,点击左边的每一个元件, 然后选择封装时的元器件,再点击右边的确定(每一个元器件确定好封装要用的元件都要点确定) ...

  4. node模块包装为Promise书写法

    1. const Promise = require('bluebird') const fs = Promise.promisifyAll(Promise.promisify(require('fs ...

  5. jmeter测试服务器压力

    http://blog.csdn.net/BobChao0730/article/details/51352768 http://blog.csdn.net/u011943953/article/de ...

  6. Centos7 MongoDB-3.4

    MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的 关系型数据库遵循ACID规则 事务在英文中是transaction,和现实世界中的交易很类 ...

  7. 基于Python的SQLAlchemy的操作

    安装 在Python使用SQLAlchemy的首要前提是安装相应的模块,当然作为python的优势,可以到python安装目录下的scripts下,同时按住shift+加上鼠标左键,从而在菜单中打开命 ...

  8. 各种Oracle索引类型介绍

    逻辑上:Single column 单行索引Concatenated 多行索引Unique 唯一索引NonUnique 非唯一索引Function-based函数索引Domain 域索引 物理上:Pa ...

  9. C# DES (ECB模式) 加密解密 --单倍长

    加密:  调用时: Encrypt_DES16("2AF349243535BCD3", "1111111111111111"); public static s ...

  10. 启明星系统安装教程(如何在windows2012里配置IIS)

    (1)安装IIS 因为在windows2012里,安装数据库,IIS部分组件都需要.NET3.5,而默认windows2012安装时,并不会把此组件复制到电脑里 导致,后期要安装.NET3.5还需要安 ...