wpf数据验证实例及常用方法小结
虽然标题是wpf数据验证,但并不是对IDataErrorInfo、ValidationRule、属性中throw Exception这几种验证方式的介绍;
之前做项目时(例如员工工资管理),根据员工编号和年度月份验证 当月数据的唯一性,因为第一次开发wpf经验不足,所以用过几种不同的方式,并且现在用的这种方式也不是很满意,如果哪位大神有更好的办法 麻烦发个链接。
文章最后会把验证、列表的样式和验证中常使用的一些方法贴出来,方便大家使用;
列表页面 员工编号和年度月份验证
添加修改页面 填写编号选择月份后,验证不通过都是在编号处提示
一、言归正传,逐步写一下我当时的思路
1、为了实现这种需求的验证,最先想到的就是实现了ValidationRule的自定义验证类(ValidateExistLogName)能有一个属性(ValiByProperty) binding上月份中选择的值,关联月份和当前输入的员工编号来验证当月是否存在;
<Binding.ValidationRules> <tool:ValidateExistLogName ValiByProperty="{Binding CurMonth}"/> </Binding.ValidationRules>
但是只有DependencyObject派生类的DependencyProperty属性才能进行binding,于是我找到了给ValidationRule派生类的属性上binding的办法
参考链接:http://www.codeproject.com/Articles/18678/Attaching-a-Virtual-Branch-to-the-Logical-Tree-in
https://social.msdn.microsoft.com/Forums/vstudio/en-US/982e2fcf-780f-4f1c-9730-cedcd4e24320/binding-validationrules-property?forum=wpf
这种方式可能添加页面比较好实现,但是对于列表DataGrid恐怕binding起来就,也许有人说可以DataGrid的IsReadOnly=false,但是我的需求是修改页面修改的同时支持列表直接修改。
2、对实体类添加PropertyChangedEventHandler事件,这种方式可以实现,但是却不是在ValidationRule中验证,而且事件中的逻辑代码也稍较麻烦,因为e.PropertyName绑定的是datepicker控件时,需throw new Exception才能显示出来错误
列表中 初始化列表时遍历datagrid中的绑定源数据:
foreach (var item in data)
{
//为新加数据也加入事件
item.PropertyChanged -= new System.ComponentModel.PropertyChangedEventHandler(source_PropertyChanged);
item.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(source_PropertyChanged);
} 添加或者修改直接给绑定的实体类添加事件:
source.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(source_PropertyChanged);
3、期间还尝试了别的,但改动不大 基本记不清楚了,最后还是在派生自ValidationRule的类中添加需要验证的实体属性
public class ValidateExistCurMonthOrLogName : ValidationRule
{
public object Entity { get; set; }
public int ValiPropertyType { get; set; }//1验证LogName,2验证CurMonth
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if(this.ValiPropertyType==1)
{
int tmp;
if (string.IsNullOrEmpty(value as string) || string.IsNullOrWhiteSpace(value as string))
{
return new ValidationResult(false, "不能为空!");
}
else if (!int.TryParse(value as string, out tmp))
{
return new ValidationResult(false, "请输入正确的数字!");
}
else if(...验证是否已存在)
.........
}
......... }
} 1、DataGrid列表
//在单元格开始编辑的时候,把要验证的实体赋值
dataGrid.PreparingCellForEdit += delegate(object sender, DataGridPreparingCellForEditEventArgs e)
{
//记录原始状态
AllowanceData model = e.Row.Item as AllowanceData;
allowanceDataHelper.SourceToModel(model, originalModel);
//获取cell
DataGridCell cell = OperateControlHelper.GetCell(dataGrid, e.Row.GetIndex(), e.Column.DisplayIndex);
//判断当前编辑的是TextBox还是DatePicker
DatePicker dp = OperateControlHelper.GetVisualChild<DatePicker>(cell);
TextBox txb = OperateControlHelper.GetVisualChild<TextBox>(cell);
FrameworkElement node;
DependencyProperty depenPro;
if (dp != null)
{
node = dp;
depenPro = DatePicker.TextProperty;
}
else if (txb != null)
{
node = txb;
depenPro = TextBox.TextProperty;
}
else
{
throw new Exception("...");
}
InitValidateExistCurMonthOrLogName(node, new ValidateExistCurMonthOrLogName() { Entity = originalModel });
} 2、添加或修改页面直接调用
InitValidateExistCurMonthOrLogName(txbLogName, new ValidateExistCurMonthOrLogName() { Entity = source });
InitValidateExistCurMonthOrLogName(dpCurMonth, new ValidateExistCurMonthOrLogName() { Entity = source }); //调用
void InitValidateExistCurMonthOrLogName(FrameworkElement node, ValidateExistCurMonthOrLogName modelArgs)
{
//获取类型
DependencyProperty depenPro;
if (node is DatePicker)
{
depenPro = DatePicker.TextProperty;
}
else
{
depenPro = TextBox.TextProperty;
}
//获取自定义验证
ValidateExistCurMonthOrLogName validateLogNameOrCurMonth = node.GetBindingExpression(depenPro).ParentBinding.ValidationRules.Select(v =>
{
if (v is ValidateExistCurMonthOrLogName)
return v;
return null;
}).FirstOrDefault() as ValidateExistCurMonthOrLogName;
if (validateLogNameOrCurMonth != null)
{
validateLogNameOrCurMonth.Entity = modelArgs.Entity;
}
}
二、styel
1、列表的样式
<Style TargetType="DataGrid">
<Setter Property="AutoGenerateColumns" Value="False"/>
<!--<Setter Property="IsReadOnly" Value="True"/>-->
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="CanUserSortColumns" Value="False"/>
<Setter Property="CanUserResizeColumns" Value="False"/>
<Setter Property="CanUserResizeRows" Value="False"/>
<Setter Property="SelectionMode" Value="Extended"/>
<Setter Property="SelectionUnit" Value="FullRow"/>
<Setter Property="CanUserReorderColumns" Value="False"/>
<Setter Property="AlternationCount" Value="2"/>
<Setter Property="RowHeaderWidth" Value="0"/>
<Setter Property="CanUserAddRows" Value="False"/> <Setter Property="CanUserResizeColumns" Value="false"/>
<Setter Property="Background" Value="#b7e9fe" />
<Setter Property="BorderBrush" Value="gray" />
<Setter Property="HorizontalGridLinesBrush">
<Setter.Value>
<SolidColorBrush Color="#85cfee"/>
</Setter.Value>
</Setter>
<Setter Property="VerticalGridLinesBrush">
<Setter.Value>
<SolidColorBrush Color="#85cfee"/>
</Setter.Value>
</Setter>
</Style> <Style TargetType="DataGridColumnHeader">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="28" />
<Setter Property="Foreground" Value="#07638a" />
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="12" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridColumnHeader">
<Border x:Name="BackgroundBorder" BorderThickness="0,1,0,1"
BorderBrush="#85cfee"
Width="Auto">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ContentPresenter Margin="0,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Path x:Name="SortArrow" Visibility="Collapsed" Data="M0,0 L1,0 0.5,1 z" Stretch="Fill" Grid.Column="2" Width="8" Height="6" Fill="White" Margin="0,0,50,0"
VerticalAlignment="Center" RenderTransformOrigin="1,1" />
<Rectangle Width="1" Fill="#85cfee" HorizontalAlignment="Right" Grid.ColumnSpan="1" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Height" Value="25"/>
</Style> <Style TargetType="DataGridRow">
<Setter Property="Background" Value="#FFFFFF" />
<Setter Property="Height" Value="25"/>
<Setter Property="Foreground" Value="#07638a" />
<Style.Triggers>
<Trigger Property="AlternationIndex" Value="0" >
<Setter Property="Background" Value="#FFFFFF" />
</Trigger>
<Trigger Property="AlternationIndex" Value="1" >
<Setter Property="Background" Value="#e1f5fd" />
</Trigger> <Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightGray"/>
</Trigger> <Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
</Trigger>
</Style.Triggers>
</Style>
2、DataGrid的ErrorTemplate
<Style x:Key="textBoxErrorTemplateInDataGrid" TargetType="{x:Type TextBox}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="BorderBrush" Value="#6bc4e9"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="MinWidth" Value="80"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Ellipse DockPanel.Dock="Right"
Width="15" Height="15" Margin="-25,0,0,0" StrokeThickness="1" Fill="Red" >
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<GradientStop Color="#FFFA0404" Offset="0"/>
<GradientStop Color="#FFC9C7C7" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<TextBlock DockPanel.Dock="Right" ToolTip="{Binding ElementName=errorHint,Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
Foreground="White" FontSize="11pt" Margin="-15,5,0,0" FontWeight="Bold">!
<TextBlock.Triggers>
</TextBlock.Triggers>
</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="errorHint" />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
3、添加修改的ErrorTemplate
<Style x:Key="datePickerErrorTemplate" TargetType="{x:Type DatePicker}">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="BorderBrush" Value="#6bc4e9"/>
<Setter Property="Foreground" Value="#07638a"/>
<Setter Property="Margin" Value="5, 10, 0, 0"/>
<Setter Property="Width" Value="120"/>
<Setter Property="Height" Value="23"/>
<Setter Property="BorderThickness" Value="1"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right" Margin="5,0,0,0" VerticalAlignment="Center" Foreground="Red" FontSize="12"
Text="{Binding ElementName=errorHint, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}">
</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="errorHint" />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
三、wpf验证中常用的方法
1、获取自定义验证类
public YourValidationRule GetValidationRule(FrameworkElement node,DependencyProperty depenPro)
{
YourValidationRule vr = node.GetBindingExpression(depenPro).ParentBinding.ValidationRules.Select(v =>
{
if (v is YourValidationRule )
return v; return null;
}).FirstOrDefault() as YourValidationRule ;
return vr;
}
2、递归判断是否有未通过验证的控件
public static bool IsHasError(DependencyObject node, out string errorMsg)
{
errorMsg = string.Empty;
if (node != null)
{
bool isValid = !Validation.GetHasError(node);
if (!isValid)
{
if (node is IInputElement)
if (((IInputElement)node).IsEnabled == true)
{
ValidationError ve = Validation.GetErrors(node).FirstOrDefault();
if (ve != null)
{
errorMsg = ve.ErrorContent.ToString();
}
Keyboard.Focus((IInputElement)node);
return false;
}
}
}
foreach (object subnode in LogicalTreeHelper.GetChildren(node))
{
if (subnode is DependencyObject)
{
if (IsHasError((DependencyObject)subnode, out errorMsg) == false) return false;
}
}
return true;
}
3、向控件中添加错误验证
public static void AddValidationError<T>(FrameworkElement fe, DependencyProperty dp, string errorMsg) where T : ValidationRule, new()
{
ValidationError validationError =
new ValidationError(new NotConvertInt(),
fe.GetBindingExpression(dp)); validationError.ErrorContent = "该用户在本月已存在数据!"; Validation.MarkInvalid(
fe.GetBindingExpression(dp),
validationError);
}
4、清空控件中的错误验证
public static void ClearValidationError(FrameworkElement fe, DependencyProperty dp)
{
Validation.ClearInvalid(fe.GetBindingExpression(dp));
}
5、从DataGrid获得Cell
public static DataGridCell GetCell(DataGrid dataGrid, int row, int column)
{
DataGridRow rowContainer = GetRow(dataGrid, row);
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
if (presenter == null)
{
dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]);
presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
}
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
return cell;
}
return null;
}
6、从DataGrid获得Row
public static DataGridRow GetRow(DataGrid dataGrid, int index)
{
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
dataGrid.UpdateLayout();
dataGrid.ScrollIntoView(dataGrid.Items[index]);
row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
7、获取指定索引项的元素
public static TContainer GetContainerFromIndex<TContainer>
(ItemsControl itemsControl, int index)
where TContainer : DependencyObject
{
return (TContainer)
itemsControl.ItemContainerGenerator.ContainerFromIndex(index);
}
8、从DataGrid中获取正在编辑的Row
public static DataGridRow GetEditingRow(DataGrid dataGrid)
{
var sIndex = dataGrid.SelectedIndex;
if (sIndex >= 0)
{
var selected = GetContainerFromIndex<DataGridRow>(dataGrid, sIndex);
if (selected.IsEditing) return selected;
} for (int i = 0; i < dataGrid.Items.Count; i++)
{
if (i == sIndex) continue;
var item = GetContainerFromIndex<DataGridRow>(dataGrid, i);
if (item.IsEditing) return item;
} return null;
}
wpf数据验证实例及常用方法小结的更多相关文章
- WPF数据验证方式
WPF有两种数据验证的方式: 1 在数据对象上进行验证:普通属性验证或者实现IDataErrorInfo接口 2 可以再绑定规则上进行验证:ExceptionValidationRule异常验证规则 ...
- WPF数据验证
当填写表单时,需要对填写的内容进行验证,检查数据是否符合要求,比如字符串的长度.日期的格式.数字等.WPF支持自定义验证规则,并提供可视化反馈,以便在输入无效值时向用户发出通知. 下面的示例将演示一个 ...
- WPF数据验证(4)——响应与获取验证错误
1780 前面的示例中,有关用户接受到错误的唯一指示是在违反规则的文本框周围的红色轮廓.为了提供更多信息,可以处理 Error 事件,但存储或清除错误时会引发该事件,但前提是必须确保已将 Bindin ...
- WPF数据验证(5)―― 错误模板
<Style TargetType="{x:Type TextBox}"> <Setter Property="Validatio ...
- 【WPF】数据验证
原文:[WPF]数据验证 引言 数据验证在任何用户界面程序中都是不可缺少的一部分.在WPF中,数据验证更是和绑定紧紧联系在一起,下面简单介绍MVVM模式下常用的几种验证方式. 错误信息显示 ...
- Silverlight实例教程 - Validation客户端同步数据验证(转载)
摘要:在Silverlight 4中,Silverlight Validation有相对的改进,本篇将介绍Silverlight 4中新加入的验证机制功能,IDataErrorInfo客户端同步验证机 ...
- WPF中的数据验证
数据验证 WPF的Binding使得数据能够在数据源和目标之间流通,在数据流通的中间,便能够对数据做一些处理. 数据转换和数据验证便是在数据从源到目标 or 从目标到源 的时候对数据的验证和转换. V ...
- Silverlight实例教程 – Datagrid,Dataform数据验证和ValidationSummary(转载)
Silverlight 4 Validation验证实例系列 Silverlight实例教程 - Validation数据验证开篇 Silverlight实例教程 - Validation数据验证基础 ...
- MVC数据验证使用小结
原文:MVC数据验证使用小结 描述:MVC数据验证使用小结 内容:display,Required,stringLength,Remote,compare,RegularExpression 本人最近 ...
随机推荐
- 【P2052】道路修建(树形+搜索)
这个题看上去高大上,实际上就是一个大水题.怎么说呢,这个题思路可能比较难搞,代码实现难度几乎为0. 首先我们可以发现这是一棵树,然后问其中任意一条边左右两边的点的数量之差的绝对值,实际上,无论两边的点 ...
- 泛型学习第四天——List泛型终结:什么是List泛型,泛型筛选,泛型排序
为什么要用泛型集合? 在C# 2.0之前,主要可以通过两种方式实现集合: a.使用ArrayList 直接将对象放入ArrayList,操作直观,但由于集合中的项是Object类型,因此每次使用都必须 ...
- mysql数据简单去重
我有一个 foo 表,定义了如下几个字段:id / a / b,其中 id 是主键,a,b 原本应该具有唯一性, 但因为程序 bug 导致 a,b 内容有重复,现在我要在 a,b 上加唯一索引,请问如 ...
- 代码题(45)— 下一个排列、第k个排列
1.31. 下一个排列 实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列. 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列). 必须原地修改,只 ...
- 《Advanced Bash-scripting Guide》学习(二):测试脚本调用的参数是否正确
本文所选的例子来自于<Advanced Bash-scripting Gudie>一书,译者 杨春敏 黄毅 #!/bin/bash E_WRONG_ARGS=85 script_param ...
- TCP/IP详解学习笔记(4)-ICMP协议,ping和Traceroute【转】
转自:http://blog.csdn.net/goodboy1881/article/details/670761 1.IMCP协议介绍 前面讲到了,IP协议并不是一个可靠的协议(是一种尽力传送的协 ...
- HANA Architecture
1 HANA 是基于内存计算的.行列都支持.使用列存储,列存储的特点是高压缩,查询快,节约空间, ---SAP HANA supports both, but is particularly opti ...
- 设置cookie的保存时间 下一篇
设置cookie的保存时间,通过cookie的expires性质指定一个终止时间就可以了.也就是说,你在设置cookie的时候,你的cookie字串要像下面这样组合: var d= new Date( ...
- Spring_总结_03_装配Bean(四)_导入与混合配置
一.前言 本文承接上一节:Spring_总结_03_装配Bean(三)之XML配置 在典型的Spring应用中,我们可能会同时使用自动化和显示配置.同时,可能在某些场景下我们需要混合使用JavaCon ...
- jsp中向浏览器页面输出的方式总结
jsp中百分号内输出 不需要有JavaScript标签 1.因为jsp就是包含在html 里面,所以什么都不干时,就是在body里面输出html内容 2.百分号 内是JavaScript代码?java ...