WPF 显示验证错误的默认方式是在控件周围绘制红色边框。通常需要对此方法进行自定义,以通过其他方式来显示错误。而且,默认情况下不会显示与验证错误关联的错误消息。常见的要求是仅当存在验证错误时才在工具提示中显示错误消息。通过将 Styles 和一组与验证关联的附加属性进行组合,可以相当轻松地自定义验证错误显示。

前台xaml:

 

[csharp] view plain copy
 
  1. <ResourceDictionary  
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"   
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">  
  4.     <!-- 应该在此定义资源字典条目。-->  
  5.     <LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" StartPoint="0,0" MappingMode="Absolute">  
  6.         <GradientStop Color="#ABADB3" Offset="0.05"/>  
  7.         <GradientStop Color="#E2E3EA" Offset="0.07"/>  
  8.         <GradientStop Color="#E3E9EF" Offset="1"/>  
  9.     </LinearGradientBrush>  
  10.     <ControlTemplate x:Key="validationTemplate">  
  11.   
  12.     </ControlTemplate>  
  13.     <Style BasedOn="{x:Null}" TargetType="{x:Type TextBox}">  
  14.         <Setter Property="Validation.ErrorTemplate" Value="{StaticResource validationTemplate}" />  
  15.         <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>  
  16.         <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>  
  17.         <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>  
  18.         <Setter Property="BorderThickness" Value="1"/>  
  19.         <Setter Property="Padding" Value="1"/>  
  20.         <Setter Property="AllowDrop" Value="true"/>  
  21.         <Setter Property="FocusVisualStyle" Value="{x:Null}"/>  
  22.         <Setter Property="Template">  
  23.             <Setter.Value>  
  24.                 <ControlTemplate TargetType="{x:Type TextBox}">  
  25.                     <Grid x:Name="root">  
  26.                         <Grid.ColumnDefinitions>  
  27.                             <ColumnDefinition Width="*"/>  
  28.                             <ColumnDefinition Width="1"/>  
  29.                         </Grid.ColumnDefinitions>  
  30.                         <!--<Border x:Name="Border" Background="White" BorderBrush="Gray" BorderThickness="0" Padding="2" CornerRadius="1">-->  
  31.                                 <Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding IsMouseOver}">  
  32.                                     <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>  
  33.                                 </Microsoft_Windows_Themes:ListBoxChrome>  
  34.                             <!--</Border>-->  
  35.                         <Border x:Name="border"  BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1" Visibility="Collapsed"  HorizontalAlignment="Stretch" Margin="0" Width="Auto">  
  36.   
  37.                             <Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">  
  38.                                 <Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/>  
  39.                                 <Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/>  
  40.                             </Grid>  
  41.                         </Border>  
  42.                         <Popup x:Name="popup" Placement="Right" IsOpen="False">  
  43.                             <Border x:Name="border1_Copy" Width="Auto" Height="Auto" Background="Red" BorderThickness="0" >  
  44.                                 <TextBlock TextWrapping="NoWrap" Text="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>  
  45.                             </Border>  
  46.                             <!--<Grid Width="50" Height="20" Background="Red"/>-->  
  47.   
  48.                         </Popup>  
  49.                         <!--<Popup x:Name="popup"  Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}"  Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Top" IsOpen="False" StaysOpen="True" AllowsTransparency="True">  
  50.                             <Border x:Name="border1_Copy" BorderThickness="1" Margin="0" Background="Red" CornerRadius="2"  HorizontalAlignment="Stretch" Opacity="0" RenderTransformOrigin="0.5,0.5" Height="Auto" Width="Auto">  
  51.                                 <Border.RenderTransform>  
  52.                                     <TransformGroup>  
  53.                                         <ScaleTransform/>  
  54.                                         <SkewTransform/>  
  55.                                         <RotateTransform/>  
  56.                                         <TranslateTransform X="10"/>  
  57.                                     </TransformGroup>  
  58.                                 </Border.RenderTransform>  
  59.                                 <Border.Effect>  
  60.                                     <DropShadowEffect Direction="-90" BlurRadius="5" Color="#FF808080" ShadowDepth="1"/>  
  61.                                 </Border.Effect>  
  62.                                 <TextBlock TextWrapping="NoWrap" Text="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>  
  63.                             </Border>  
  64.                         </Popup>-->  
  65.                     </Grid>  
  66.                     <ControlTemplate.Triggers>  
  67.                         <Trigger Property="Validation.HasError" Value="True">  
  68.                             <Setter Property="Visibility" TargetName="border" Value="Visible"/>  
  69.                         </Trigger>  
  70.                         <MultiTrigger>  
  71.                             <MultiTrigger.Conditions>  
  72.                                 <Condition Property="Validation.HasError" Value="True"/>  
  73.                                 <Condition Property="IsFocused" Value="True"/>  
  74.                             </MultiTrigger.Conditions>  
  75.                             <Setter Property="IsOpen" TargetName="popup" Value="True"/>  
  76.                         </MultiTrigger>  
  77.                     </ControlTemplate.Triggers>  
  78.                 </ControlTemplate>  
  79.             </Setter.Value>  
  80.         </Setter>  
  81.     </Style>  
  82.     <!--<Style TargetType="TextBox">  
  83.         <Style.Triggers>  
  84.   
  85.             <Trigger Property="Validation.HasError"   
  86.               Value="True">  
  87.   
  88.                 <Setter Property="ToolTip">  
  89.   
  90.                     <Setter.Value>  
  91.   
  92.                         <Binding Path="(Validation.Errors).CurrentItem.ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" />  
  93.   
  94.                     </Setter.Value>  
  95.   
  96.                 </Setter>  
  97.   
  98.             </Trigger>  
  99.   
  100.         </Style.Triggers>  
  101.   
  102.     </Style>-->  
  103. </ResourceDictionary>  


后台代码:

 

 

[csharp] view plain copy
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Windows;  
  6. using System.Windows.Controls;  
  7. using System.Windows.Data;  
  8. using System.Windows.Documents;  
  9. using System.Windows.Input;  
  10. using System.Windows.Media;  
  11. using System.Windows.Media.Imaging;  
  12. using System.Windows.Navigation;  
  13. using System.Windows.Shapes;  
  14.   
  15. namespace WpfApplication11111  
  16. {  
  17.     /// <summary>  
  18.     /// UserControl2.xaml 的交互逻辑  
  19.     /// </summary>  
  20.     public partial class UserControl2 : UserControl  
  21.     {  
  22.         private UserInfo _UserInfo;  
  23.         public UserControl2()  
  24.         {  
  25.             InitializeComponent();  
  26.             this.Loaded += new RoutedEventHandler(UserControl2_Loaded);  
  27.         }  
  28.   
  29.         void UserControl2_Loaded(object sender, RoutedEventArgs e)  
  30.         {  
  31.             _UserInfo = new UserInfo();  
  32.             this.DataContext = _UserInfo;  
  33.         }  
  34.   
  35.         private void btnSave_Click(object sender, RoutedEventArgs e)  
  36.         {  
  37.             //txtName.Visibility = Visibility.Collapsed;  
  38.             UserControl1 _UserControl1 = new UserControl1();  
  39.             grid.Children.Add(_UserControl1);  
  40.             string _name = _UserInfo.Name;  
  41.             string _pass = _UserInfo.Pass;  
  42.         }  
  43.     }  
  44. }  

 

实体类:

 

 

[csharp] view plain copy
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.ComponentModel;  
  6. using System.ComponentModel.DataAnnotations;  
  7.   
  8. namespace WpfApplication11111  
  9. {  
  10.     public class UserInfo : ValidationUtility, INotifyPropertyChanged  
  11.     {  
  12.         #region 数据更新通知  
  13.   
  14.         public event PropertyChangedEventHandler PropertyChanged;  
  15.   
  16.         private void NotifyPropertyChange(string propertyName)  
  17.         {  
  18.             if (PropertyChanged != null)  
  19.             {  
  20.                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));  
  21.             }  
  22.         }  
  23.  
  24.         #endregion  
  25.   
  26.         private string _Name;  
  27.   
  28.         [Required(ErrorMessage = "[登录名]内容不能为空!")]  
  29.         [StringLength(255, ErrorMessage = "[登录名]内容最大允许255个字符!")]  
  30.         [RegularExpression("^[A-Za-z0-9]+$", ErrorMessage = "[登录名]格式不正确!")]  
  31.         /// <summary>  
  32.         ///   
  33.         /// </summary>  
  34.         public string Name  
  35.         {  
  36.             get { return _Name; }  
  37.             set  
  38.             {  
  39.                 //Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Name" });  
  40.                 //if (string.IsNullOrEmpty(value))  
  41.                 //{  
  42.                 //    throw new Exception("用户名不能为空.");  
  43.                 //}  
  44.                 _Name = value;  
  45.                 NotifyPropertyChange("Name");  
  46.             }  
  47.         }  
  48.   
  49.         private string _Pass;  
  50.         [Required(ErrorMessage = "[密码]内容不能为空!")]  
  51.         [StringLength(255, ErrorMessage = "[密码]内容最大允许255个字符!")]  
  52.         [RegularExpression("^[A-Za-z0-9]+$", ErrorMessage = "[密码]格式不正确!")]  
  53.         /// <summary>  
  54.         ///   
  55.         /// </summary>  
  56.         public string Pass  
  57.         {  
  58.             get { return _Pass; }  
  59.             set  
  60.             {  
  61.                 //if (string.IsNullOrEmpty(value))  
  62.                 //{  
  63.                 //    throw new Exception("密码不能为空.");  
  64.                 //}  
  65.                 _Pass = value;  
  66.                 NotifyPropertyChange("Pass");  
  67.             }  
  68.         }  
  69.   
  70.     }  
  71. }  

 

ValidationUtility.cs

 

 

[csharp] view plain copy
 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.ComponentModel;  
  6. using System.Reflection;  
  7. using System.ComponentModel.DataAnnotations;  
  8.   
  9. namespace WpfApplication11111  
  10. {  
  11.     public class ValidationUtility : IDataErrorInfo  
  12.     {  
  13.         public string Error  
  14.         {  
  15.             get { return _error; }  
  16.         }  
  17.   
  18.         public string _error;  
  19.   
  20.         public string this[string columnName]  
  21.         {  
  22.             get  
  23.             {  
  24.                 Type tp = this.GetType();  
  25.                 PropertyInfo pi = tp.GetProperty(columnName);  
  26.                 var value = pi.GetValue(this, null);  
  27.                 object[] Attributes = pi.GetCustomAttributes(false);  
  28.                 if (Attributes != null && Attributes.Length > 0)  
  29.                 {  
  30.                     foreach (object attribute in Attributes)  
  31.                     {  
  32.                         if (attribute is ValidationAttribute)  
  33.                         {  
  34.                             ValidationAttribute vAttribute = attribute as ValidationAttribute;  
  35.                             if (!vAttribute.IsValid(value))  
  36.                             {  
  37.                                 _error = vAttribute.ErrorMessage;  
  38.                                 return _error;  
  39.                             }  
  40.                         }  
  41.                     }  
  42.                 }  
  43.                 return null;  
  44.             }  
  45.         }  
  46.     }  
  47. }  

追加PasswordBox验证

 

[csharp] view plain copy
 
    1. <Style TargetType="{x:Type PasswordBox}">  
    2.         <Setter Property="Validation.ErrorTemplate" Value="{StaticResource validationTemplate}" />  
    3.         <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>  
    4.         <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>  
    5.         <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>  
    6.         <Setter Property="FontFamily" Value="Times New Roman"/>  
    7.         <Setter Property="PasswordChar" Value="●"/>  
    8.         <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>  
    9.         <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>  
    10.         <Setter Property="BorderThickness" Value="1"/>  
    11.         <Setter Property="HorizontalContentAlignment" Value="Left"/>  
    12.         <Setter Property="Padding" Value="1"/>  
    13.         <Setter Property="FocusVisualStyle" Value="{x:Null}"/>  
    14.         <Setter Property="AllowDrop" Value="true"/>  
    15.         <Setter Property="Template">  
    16.             <Setter.Value>  
    17.                 <ControlTemplate TargetType="{x:Type PasswordBox}">  
    18.                     <Grid x:Name="root">  
    19.                         <Grid.ColumnDefinitions>  
    20.                             <ColumnDefinition Width="*"/>  
    21.                             <ColumnDefinition Width="1"/>  
    22.                         </Grid.ColumnDefinitions>  
    23.                         <!--<Border x:Name="Border" Background="White" BorderBrush="Gray" BorderThickness="0" Padding="2" CornerRadius="1">-->  
    24.                             <Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding IsMouseOver}">  
    25.                                 <ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>  
    26.                             </Microsoft_Windows_Themes:ListBoxChrome>  
    27.                         <!--</Border>-->  
    28.                         <Border x:Name="border"  BorderBrush="#FFDB000C" BorderThickness="1" CornerRadius="1" Visibility="Collapsed"  HorizontalAlignment="Stretch" Margin="0" Width="Auto">  
    29.   
    30.                             <Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12">  
    31.                                 <Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/>  
    32.                                 <Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/>  
    33.                             </Grid>  
    34.                         </Border>  
    35.                         <Popup x:Name="popup" Placement="Right" IsOpen="False">  
    36.                             <Border x:Name="border1_Copy" Width="Auto" Height="Auto" Background="Red" BorderThickness="0" >  
    37.                                 <TextBlock TextWrapping="NoWrap" Text="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>  
    38.                             </Border>  
    39.                         </Popup>  
    40.                     </Grid>  
    41.                     <ControlTemplate.Triggers>  
    42.                         <Trigger Property="Validation.HasError" Value="True">  
    43.                             <Setter Property="Visibility" TargetName="border" Value="Visible"/>  
    44.                         </Trigger>  
    45.                         <MultiTrigger>  
    46.                             <MultiTrigger.Conditions>  
    47.                                 <Condition Property="Validation.HasError" Value="True"/>  
    48.                                 <Condition Property="IsFocused" Value="True"/>  
    49.                             </MultiTrigger.Conditions>  
    50.                             <Setter Property="IsOpen" TargetName="popup" Value="True"/>  
    51.                         </MultiTrigger>  
    52.                     </ControlTemplate.Triggers>  
    53.                 </ControlTemplate>  
    54.             </Setter.Value>  
    55.         </Setter>  
    56.     </Style> 
    57. 代码下载地址:

      http://download.csdn.net/detail/hwt0101/5070730