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.


 
<ControlTemplate x:Key="ErrorToolTipTemplate_1">
<ControlTemplate.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
</ControlTemplate.Resources>
<DockPanel LastChildFill="true">
<Border Height="Auto"
Margin="5,0,0,0"
Background="#DC000C"
CornerRadius="3"
DockPanel.Dock="right">
<TextBlock Style="{StaticResource textblockErrorTooltip}"
Text="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Border>
<AdornedElementPlaceholder Name="customAdorner">
<Border BorderBrush="#DC000C" BorderThickness="1.3" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
 

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.

<Style TargetType="TextBox">
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Width" Value="150" />
<Setter Property="Height" Value="30" />
<Setter Property="Validation.ErrorTemplate"
Value="{DynamicResource ErrorToolTipTemplate_1}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>

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.

public class InputValidationViewModel : ViewModelBase
{
public InputValidationViewModel()
{
}
private string employeeName;
public string EmployeeName
{
get { return employeeName; }
set { employeeName = value; RaisePropertyChanged("EmployeeName"); }
}
private string email;
public string Email
{
get { return email; }
set {email = value; RaisePropertyChanged("Email"); }
}
private long phoneNumber;
public long PhoneNumber
{
get { return phoneNumber; }
set { phoneNumber = value; RaisePropertyChanged("PhoneNumber"); }
}
private bool IsValidEmailAddress
{
get { return emailRegex.IsMatch(Email); }
}
}
 

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


 
public class InputValidationViewModel : ViewModelBase, IDataErrorInfo
{
private Regex emailRegex = new Regex(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$");
public InputValidationViewModel()
{
} private string error = string.Empty;
public string Error
{
get { return error; }
}
public string this[string columnName]
{
get
{
error = string.Empty;
if (columnName == "EmployeeName" && string.IsNullOrWhiteSpace(EmployeeName))
{
error = "Employee name is required!";
}
else if (columnName == "PhoneNumber" && PhoneNumber == 0)
{
error = "Phone number is required!";
}
else if (columnName == "PhoneNumber" && PhoneNumber.ToString().Length > 10)
{
error = "Phone number must have less than or equal to 10 digits!";
}
else if (columnName == "Email" && string.IsNullOrWhiteSpace(Email))
{
error = "Email address is required!";
}
else if (columnName == "Email" && !IsValidEmailAddress)
{
error = "Please enter valid email address!";
}
return error; } }
}

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


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

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 :

 
<Border x:Name="ValidationErrorElement"
BorderBrush="#FFDB000C"
BorderThickness="1.2"
CornerRadius="1"
ToolTip="{Binding ElementName=customAdorner,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<Grid Width="12"
Height="12"
Margin="1,-4,-4,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent">
<Path Margin="1,3,0,0"
Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z"
Fill="#FFDC000C" />
<Path Margin="1,3,0,0"
Data="M 0,0 L2,0 L 8,6 L8,8"
Fill="#ffffff" />
</Grid>
</Border>
<Border Grid.Column="0"
Width="15"
Height="15"
Margin="0 0 3 0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Background="Red"
CornerRadius="10"
ToolTip="{Binding ElementName=customAdorner,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
<TextBlock HorizontalAlignment="center"
VerticalAlignment="center"
FontWeight="Bold"
Foreground="white"
Text="!" />
</Border>
 
 

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. 洛谷P1432 倒水问题(CODEVS.1226)

    To 洛谷.1432 倒水问题 题目背景 In the movie "Die Hard 3", Bruce Willis and Samuel L. Jackson were co ...

  2. 洛谷.1110.[ZJOI2007]报表统计(Splay Heap)

    题目链接 附纯SplayTLE代码及主要思路: /* 可以看做序列有n段,Insert是每次在每一段最后插入一个元素 只有插入,没有删除,所以插入一个元素对于询问1影响的只有该元素与前边一个元素(同段 ...

  3. php date_default_timezone_set()设置时区

    <?php echo function_exists(date_default_timezone_set)."<br>";//在这他总是返回1,这函数是判断这里面 ...

  4. Linux 下 make 命令 及 make 笔记

    Linux 下 make 命令是系统管理员和程序员用的最频繁的命令之一.管理员用它通过命令行来编译和安装很多开源的工具,程序员用它来管理他们大型复杂的项目编译问题.本文我们将用一些实例来讨论 make ...

  5. GPSCamera隐私声明

    GPSCamera获取了以下敏感隐私权限用于照片水印展示: 1:修改或删除您的SD卡中的内容 2:访问确切位置信息(使用 GPS 和网络进行定位) 3:访问大致位置信息(使用网络进行定位) 4:拍摄照 ...

  6. E: Unable to locate package openjdk-8-jdk 及java version 切换

    在unbuntu14.04系统上安装 Open JDK 8 时遇到了如下问题: $ -jdk Reading package lists... Done Building dependency tre ...

  7. Unity脚本-Rotate旋转相关知识点

    1,Transform旋转   transform.Rotate(X, Y, Z);//分别绕X,Y,Z轴旋转,可写为绕某个轴旋转,栗子transform.Rotate(0, 90, 0);   tr ...

  8. db2笔记

    第七章:数据库备份与恢复 (恢复的概念,db2日志,数据库和表空间的备份,数据库和表空间的恢复,数据库和表空间的前滚,recover使用程序,数据库重建,监控备份恢复和复原,优化备份恢复和复原)1) ...

  9. C# 匿名类型如何使用

  10. The op amp module