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. HTTP那些事儿

    一.HTTP和HTTPSHTTP协议通常承载于TCP协议之上,在HTTP和TCP之间添加一个安全协议层(SSL或TSL),这个时候,就成了我们常说的HTTPS.HTTP是超文本传输协议,信息是明文传输 ...

  2. JSONObject基本内容(二)

    参考内容:http://swiftlet.net/archives/category/json  十分感谢!!! 这部分的内容主要是讲述 javaBean转换为JSONObect时,如果有些属性不需要 ...

  3. HDU.5909.Tree Cutting(树形DP FWT/点分治)

    题目链接 \(Description\) 给定一棵树,每个点有权值,在\([0,m-1]\)之间.求异或和为\(0,1,...,m-1\)的非空连通块各有多少个. \(n\leq 1000,m\leq ...

  4. 洛谷.1251.餐巾计划问题(费用流SPFA)

    题目链接 /* 每一天的餐巾需求相当于必须遍历某些点若干次 设q[i]为Dayi需求量 (x,y)表示边x容y费 将每个点i拆成i,i',由i'->T连(q[i],0)的边,表示求最大流的话一定 ...

  5. 2553 ACM N皇后 回溯递归

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2553 中文题目,题意很简单. 思路:听说这是学习递归的经典题目,就来试试,发现自己一点想法都没有,一遇到递 ...

  6. Codechef October Challenge 2018 游记

    Codechef October Challenge 2018 游记 CHSERVE - Chef and Serves 题目大意: 乒乓球比赛中,双方每累计得两分就会交换一次发球权. 不过,大厨和小 ...

  7. boostrap常用的类

    1.col-md-push-3  :向右移动3 2.col-md-pull -9 : 向左移动9 3.clearfix: 清除元素浮动问题 4. col-md-offset-3: 向右偏移 5.pul ...

  8. jsp导出简单的excel

    在jsp中加入以下代码即可 <% String fileName = "导出excel.xls"; fileName = new String(fileName.getByt ...

  9. Qt开发的程序在没有安装Qt环境的机器上可能出现的一些问题

    Qt开发的程序在没有安装Qt环境的机器上可能出现的一些问题,如:除png外的其它类型的图片,如:jpg.ico.bmp等,还有中文乱码等问题,出现这些问题的本质是Qt对这类文件格式或编码格式的支持方式 ...

  10. iOS埋点统计

    链接: iOS无埋点数据SDK实践之路 iOS:无埋点数据SDK实践之路,看完能懂就厉害了 iOS埋点业务方案 ios 无码统计埋点 使用AOP实现iOS应用内的埋点计数 Aspects(AOP) A ...