zoukankan      html  css  js  c++  java
  • 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;
            }
    

      

  • 相关阅读:
    贪心+stack Codeforces Beta Round #5 C. Longest Regular Bracket Sequence
    暴力/DP Codeforces Beta Round #22 (Div. 2 Only) B. Bargaining Table
    DFS Codeforces Round #299 (Div. 2) B. Tavas and SaDDas
    二分搜索 Codeforces Round #299 (Div. 2) C. Tavas and Karafs
    水题 Codeforces Round #299 (Div. 2) A. Tavas and Nafas
    数学 2015百度之星初赛2 HDOJ 5255 魔法因子
    贪心/数学 2015百度之星资格赛 1004 放盘子
    模拟 2015百度之星资格赛 1003 IP聚合
    rails安装使用版本控制器的原因。
    ActiveStorage. 英文书Learnrails5.2的案例,看如何放到云上。
  • 原文地址:https://www.cnblogs.com/NotAnEmpty/p/4031636.html
Copyright © 2011-2022 走看看