WPF 输入控件 验证操作和样式模板经典样式分享

标签:
wpf验证validationit |
分类: 实用操作研究 |
输入控件往往需要验证的,通常在表单中尤为如此。wpf的验证机制相较silverlight的稍微复杂。但操作起来还行。本篇由浅入深(其实也没有很深)介绍下wpf的验证使用 并 分享几个实用的 验证样式。
先上一个比较简单的例子,来看下wpf默认情况下验证时的样子:
前台:
<</FONT>TextBox x:Name="tb_Num" Width="120" VerticalAlignment="Center">
<</FONT>TextBox.Text>
<</FONT>Binding Path="Age" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
<</FONT>Binding.ValidationRules>
<</FONT>ExceptionValidationRule/>
</</FONT>Binding.ValidationRules>
</</FONT>Binding>
</</FONT>TextBox.Text>
</</FONT>TextBox>
实体类:
public class Person
{
public int Age { get; set; }
}
后台赋值:
tb_Num.DataContext = new Person();
看下效果:
默认情况下
http://s11/mw690/002kMojxty6E0DVmFpEda&690输入控件
输入值为空
http://s10/mw690/002kMojxty6E0DVookN59&690输入控件
输入值为字母
http://s8/mw690/002kMojxty6E0DVq3lR37&690输入控件
输入值大于Int范围
http://s4/mw690/002kMojxty6E0DVsl1h73&690输入控件
可以看到,当不符合输入规则时,输入框会变红。但没有任何输入出错提示,这点跟silverlight就不一样。
上面例子中用到的方法是 ValidationRules 是wpf验证方案中最常用两种方法的一个,另一个方法是继承
IDataErrorInfo。下面的例子具体给出了这两种方法的具体使用。
方法一:使用ValidationRules
第一个例子中使用的是默认的ExceptionValidationRule,但更普遍的情况下是使用自己定义的验证规则哟!~
后台定义的自定义规则
public class RequiredRule : ValidationRule
{
private int minmunLength = -1;
private int maxmunLength = -1;
private string errorMessage;
public int MinmunLength
{
get { return minmunLength; }
set { minmunLength = value; }
}
public int MaxmunLength
{
get { return maxmunLength; }
set { maxmunLength = value; }
}
public string ErrorMessage
{
get { return errorMessage; }
set { errorMessage = value; }
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
ValidationResult result = new ValidationResult(true, null);
if (value == null)
result = new ValidationResult(false, "不能为空值!");
if (string.IsNullOrEmpty(value.ToString()))
result = new ValidationResult(false, "不能为空字符串");
string inputstring = (value ?? string.Empty).ToString();
if (inputstring.Length < this.minmunLength || (this.maxmunLength > 0 && inputstring.Length > this.maxmunLength))
result = new ValidationResult(false, this.errorMessage);
return result;
}
}
前台:
<</FONT>TextBox x:Name="textbox" Width="120" VerticalAlignment="Center" >
<</FONT>TextBox.Text >
<</FONT>Binding Path="Name" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
<</FONT>Binding.ValidationRules>
<</FONT>local:RequiredRule MinmunLength="0" MaxmunLength="10" ErrorMessage="字符串最多10个字符!"/>
</</FONT>Binding.ValidationRules>
</</FONT>Binding>
</</FONT>TextBox.Text>
</</FONT>TextBox>
后台数据绑定和实体类:
textbox.DataContext = new Person();
public class Person
{
public string Name { get; set; }
}然后为了在输入出错时,有相应内容的显示,我们是要设置TextBox的样式的。
<</FONT>ControlTemplate x:Key="ErrorTemplate">
<</FONT>Border BorderBrush="Red" BorderThickness="1">
<</FONT>AdornedElementPlaceholde
</</FONT>Border>
</</FONT>ControlTemplate>
<</FONT>Style TargetType="TextBox">
<</FONT>Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}"></</FONT>Setter>
<</FONT>Style.Triggers>
<</FONT>Trigger Property="Validation.HasError" Value="True">
<</FONT>Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}"/>
</</FONT>Trigger>
</</FONT>Style.Triggers>
</</FONT>Style>
主要需要编辑的是Validation.ErrorTemplate,那个Validation.HasError = true 时主要触发ToolTip 的显示
效果就是带有tooltip的出错提示!~
方法二:使用IDataErrorInfo
前台代码中去掉
<</FONT>Binding.ValidationRules>
<</FONT>local:RequiredRule MinmunLength="0" MaxmunLength="10" ErrorMessage="字符串最多10个字符!"/>
</</FONT>Binding.ValidationRules>
后台实体类改造:
public class BaseDataErrorInfo : IDataErrorInfo
{
private string _error;
public string this[string columnName]
{
get { return GetErrorFor(columnName); }
}
public string Error
{
get { return _error; }
set { _error = value; }
}
public virtual string GetErrorFor(string columnName)
{
return string.Empty;
}
}
public class Person : BaseDataErrorInfo
{
public string Name { get; set; }
public override string GetErrorFor(string columnName)
{
if (columnName == "Name")
if (string.IsNullOrEmpty(Name))
return "Name 不能为空";
return base.GetErrorFor(columnName);
}
}
效果等同于用第一种方法,不过,在页面Loaded的时候,就开始进行验证了。
两种方法都说明完毕了,下面提供几种 Validation.ErrorTemplate 的样式。
http://s1/mw690/002kMojxty6E0IXri0wc0&690输入控件
样式代码:
<</FONT>ControlTemplate x:Key="InputErrorTemplate">
<</FONT>DockPanel>
<</FONT>Ellipse DockPanel.Dock="Right" Margin="2,0" ToolTip="Contains invalid data" Width="10" Height="10">
<</FONT>Ellipse.Fill>
<</FONT>LinearGradientBrush>
<</FONT>GradientStop Color="#11FF1111" Offset="0" />
<</FONT>GradientStop Color="#FFFF0000" Offset="1" />
</</FONT>LinearGradientBrush>
</</FONT>Ellipse.Fill>
</</FONT>Ellipse>
<</FONT>AdornedElementPlaceholde
</</FONT>DockPanel>
</</FONT>ControlTemplate>
http://s12/mw690/002kMojxty6E0J3MWQXcb&690输入控件
样式代码:
<</FONT>ControlTemplate x:Key="validationTemplate">
<</FONT>DockPanel LastChildFill="True">
<</FONT>TextBlock DockPanel.Dock="Bottom" Foreground="Red" FontWeight="Bold"
Text="{Binding ElementName=Adorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
<</FONT>Border BorderBrush="Red" BorderThickness="1">
<</FONT>AdornedElementPlaceholde
</</FONT>Border>
</</FONT>DockPanel>
</</FONT>ControlTemplate>
http://s6/mw690/002kMojxty6E0Jaos97e5&690输入控件
样式代码:(这个带动画效果的哟!~)
<</FONT>ObjectAnimationUsingKeyF
<</FONT>DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Hidden}"/>
<</FONT>DiscreteObjectKeyFrame KeyTime="00:00:00.2000000" Value="{x:Static Visibility.Visible}"/>
<</FONT>DiscreteObjectKeyFrame KeyTime="00:00:00.4000000" Value="{x:Static Visibility.Hidden}"/>
<</FONT>DiscreteObjectKeyFrame KeyTime="00:00:00.6000000" Value="{x:Static Visibility.Visible}"/>
<</FONT>DiscreteObjectKeyFrame KeyTime="00:00:00.8000000" Value="{x:Static Visibility.Hidden}"/>
<</FONT>DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static Visibility.Visible}"/>
</</FONT>ObjectAnimationUsingKeyF
</</FONT>Storyboard>
<</FONT>ControlTemplate x:Key="ImplicateTemplate">
<</FONT>DockPanel LastChildFill="True">
<</FONT>Ellipse DockPanel.Dock="Right" ToolTip="{Binding ElementName=myTextbox, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
Width="15" Height="15" Margin="-25,0,0,0" StrokeThickness="1" Fill="Red" >
<</FONT>Ellipse.Stroke>
<</FONT>LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<</FONT>GradientStop Color="#FFFA0404" Offset="0"/>
<</FONT>GradientStop Color="#FFC9C7C7" Offset="1"/>
</</FONT>LinearGradientBrush>
</</FONT>Ellipse.Stroke>
<</FONT>Ellipse.Triggers>
<</FONT>EventTrigger RoutedEvent="FrameworkElement.Loaded">
<</FONT>BeginStoryboard Storyboard="{StaticResource FlashErrorIcon}"/>
</</FONT>EventTrigger>
</</FONT>Ellipse.Triggers>
</</FONT>Ellipse>
<</FONT>TextBlock DockPanel.Dock="Right" ToolTip="{Binding ElementName=myControl,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
Foreground="White" FontSize="11pt" Margin="-15,5,0,0" FontWeight="Bold">!
<</FONT>TextBlock.Triggers>
<</FONT>EventTrigger RoutedEvent="FrameworkElement.Loaded">
<</FONT>BeginStoryboard Storyboard="{StaticResource FlashErrorIcon}"/>
</</FONT>EventTrigger>
</</FONT>TextBlock.Triggers>
</</FONT>TextBlock>
<</FONT>Border BorderBrush="Red" BorderThickness="1">
<</FONT>AdornedElementPlaceholde
</</FONT>Border>
</</FONT>DockPanel>
</</FONT>ControlTemplate>
http://s11/mw690/002kMojxty6E0Jjem5sca&690输入控件
样式代码:(这个是效仿Silverlight的验证效果来的,有动画效果,体验很是不错)
<</FONT>local:BooleanOrConverter x:Key="BooleanOrConverter"/>
<</FONT>ControlTemplate x:Key="errorTemplateSilverlight
<</FONT>StackPanel Orientation="Horizontal">
<</FONT>Border BorderThickness="1" BorderBrush="#FFdc000c" CornerRadius="0.7" VerticalAlignment="Top">
<</FONT>Grid>
<</FONT>Polygon x:Name="toolTipCorner" Grid.ZIndex="2" Margin="-1" Points="6,6 6,0 0,0" Fill="#FFdc000c" HorizontalAlignment="Right" VerticalAlignment="Top" IsHitTestVisible="True"/>
<</FONT>Polyline Grid.ZIndex="3" Points="7,7 0,0" Margin="-1" HorizontalAlignment="Right" StrokeThickness="1.5" StrokeEndLineCap="Round" StrokeStartLineCap="Round" Stroke="White" VerticalAlignment="Top" IsHitTestVisible="True"/>
<</FONT>AdornedElementPlaceholde
</</FONT>Grid>
</</FONT>Border>
<</FONT>Border x:Name="errorBorder" Background="#FFdc000c" Margin="1,0,0,0" Opacity="0" CornerRadius="1.5" IsHitTestVisible="False" MinHeight="24" MaxWidth="267">
<</FONT>Border.Effect>
<</FONT>DropShadowEffect ShadowDepth="2.25" Color="Black" Opacity="0.4" Direction="315" BlurRadius="4"/>
</</FONT>Border.Effect>
<</FONT>TextBlock Text="{Binding ElementName=adorner,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" Foreground="White" Margin="8,3,8,3" TextWrapping="Wrap"/>
</</FONT>Border>
</</FONT>StackPanel>
<</FONT>ControlTemplate.Triggers>
<</FONT>DataTrigger Value="True">
<</FONT>DataTrigger.Binding>
<</FONT>MultiBinding Converter="{StaticResource BooleanOrConverter}">
<</FONT>Binding ElementName="adorner" Path="AdornedElement.IsKeyboardFocused" />
<</FONT>Binding ElementName="toolTipCorner" Path="IsMouseOver"/>
</</FONT>MultiBinding>
</</FONT>DataTrigger.Binding>
<</FONT>DataTrigger.EnterActions>
<</FONT>BeginStoryboard x:Name="fadeInStoryboard">
<</FONT>Storyboard>
<</FONT>DoubleAnimation Duration="00:00:00.15" Storyboard.TargetName="errorBorder" Storyboard.TargetProperty="Opacity" To="1"/>
<</FONT>ThicknessAnimation Duration="00:00:00.15" Storyboard.TargetName="errorBorder" Storyboard.TargetProperty="Margin" FillBehavior="HoldEnd" From="1,0,0,0" To="5,0,0,0">
<</FONT>ThicknessAnimation.EasingFunction>
<</FONT>BackEase EasingMode="EaseOut" Amplitude="2"/>
</</FONT>ThicknessAnimation.EasingFunction>
</</FONT>ThicknessAnimation>
</</FONT>Storyboard>
</</FONT>BeginStoryboard>
</</FONT>DataTrigger.EnterActions>
<</FONT>DataTrigger.ExitActions>
<</FONT>StopStoryboard BeginStoryboardName="fadeInStoryboard"/>
<</FONT>BeginStoryboard x:Name="fadeOutStoryBoard">
<</FONT>Storyboard>
<</FONT>DoubleAnimation Duration="00:00:00" Storyboard.TargetName="errorBorder" Storyboard.TargetProperty="Opacity" To="0"/>
</</FONT>Storyboard>
</</FONT>BeginStoryboard>
</</FONT>DataTrigger.ExitActions>
</</FONT>DataTrigger>
</</FONT>ControlTemplate.Triggers>
</</FONT>ControlTemplate>
后台用了一个Converter,用来设置触发验证
public class BooleanOrConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
foreach (object value in values)
{
if ((bool)value == true)
{
return true;
}
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}