wpf数据验证实例及常用方法小结

虽然标题是wpf数据验证,但并不是对IDataErrorInfo、ValidationRule、属性中throw Exception这几种验证方式的介绍;

之前做项目时(例如员工工资管理),根据员工编号和年度月份验证 当月数据的唯一性,因为第一次开发wpf经验不足,所以用过几种不同的方式,并且现在用的这种方式也不是很满意,如果哪位大神有更好的办法 麻烦发个链接。

文章最后会把验证、列表的样式和验证中常使用的一些方法贴出来,方便大家使用;

列表页面 员工编号和年度月份验证

添加修改页面 填写编号选择月份后,验证不通过都是在编号处提示

 

一、言归正传,逐步写一下我当时的思路

1、为了实现这种需求的验证,最先想到的就是实现了ValidationRule的自定义验证类(ValidateExistLogName)能有一个属性(ValiByProperty) binding上月份中选择的值,关联月份和当前输入的员工编号来验证当月是否存在;

1
2
3
4
5
<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才能显示出来错误

1
2
3
4
5
6
7
8
9
10
列表中 初始化列表时遍历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的类中添加需要验证的实体属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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);<br>                 //判断当前编辑的是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、列表的样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<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、获取自定义验证类

1
public  YourValidationRule GetValidationRule(FrameworkElement node,DependencyProperty depenPro)<br>{
1
2
3
4
5
<em id= "__mceDel" >YourValidationRule vr = node.GetBindingExpression(depenPro).ParentBinding.ValidationRules.Select(v =>
             {
                 if  (v  is  YourValidationRule )
          return  v;  return  null ;
            }).FirstOrDefault()  as  YourValidationRule ;<br> return  vr;<br>}</em>

2、递归判断是否有未通过验证的控件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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、向控件中添加错误验证

1
2
3
4
5
6
7
8
9
10
11
12
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、清空控件中的错误验证

1
2
3
4
public  static  void  ClearValidationError(FrameworkElement fe, DependencyProperty dp)
         {
             Validation.ClearInvalid(fe.GetBindingExpression(dp));
         }

5、从DataGrid获得Cell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

1
2
3
4
5
6
7
8
9
10
11
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、获取指定索引项的元素

1
2
3
4
5
6
7
public  static  TContainer GetContainerFromIndex<TContainer>
   (ItemsControl itemsControl,  int  index)
     where  TContainer : DependencyObject
         {
             return  (TContainer)
               itemsControl.ItemContainerGenerator.ContainerFromIndex(index);
         }

8、从DataGrid中获取正在编辑的Row

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 ;
         }

转载于:https://www.cnblogs.com/sjqq/p/7978370.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值