none
关于WPF验证的问题 RRS feed

  • 问题

  • 问题是这样的

    我在给控件绑定的时候都加上验证类了;所以在控件编辑的时候,如果不正确就会出现红框,如下图:

    但是如果没有对控件进行编辑的话,直接点击保存按钮,怎么做让验证机制生效呢?在点保存的时候,能否遍历界面上所有绑定到控件的验证类?

    2011年8月30日 11:35

答案

全部回复

  • 可以啊,我也遇到过这个问题。你不是已经实现IDataErrorInfo接口了么?每次点击按钮时候看一下实现IDataErrorInfo的类的Error属性是否为空即可 if (string.IsNullOrEmpty(Class.Error))。

        public string Error { get { throw new NotImplementedException(); } }
        public string this[string columnName]
        {
          get
          {
            if (columnName == "Name")
              if (string.IsNullOrEmpty(Name)) return "Can not be empty";
            return "";
          }
    
        }
    

     

     

    2011年8月30日 11:52
  • 产品类型里面实现IDataErrorInfo接口实现验证

    保存绑定一个CanExecuteCommand验证所有的输入是否都符合条件

    如果不符合 禁用保存按钮

    2011年8月30日 13:38
  • 不好意思; 我的数据绑定并不是用的数据结构类;而是在后台动态加载数据的绑定关系,如下代码:

    Binding testBinding = new Binding();

    testBinding.ValidationRules.Add(new SOTCBindingValidation.IPv4ValidationRule());//添加验证,根据数据类型添加不一样的验证类

    testBinding.Mode = BindingMode.TwoWay;

    testBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

    testBinding.Path = new PropertyPath("[" + myTextBox.Name + "].Permit");//绑定源路径

    testBinding.Source = dic; //绑定源,

    myTextBox.SetBinding(TextBox.TextProperty ,testBinding );//绑定目标属性

    数据验证也是加的数据验证类继承ValidationRule。


    public class SOTCBindingValidation
        {
            public class IPv4ValidationRule : ValidationRule
              {
                public override ValidationResult Validate(object value, CultureInfo cultureInfo)
                {
                  var str = value as string;
                  if (String.IsNullOrEmpty(str))
                  {
                      MessageBox.Show("请输入日期。");
                    //return new ValidationResult(false,
                    //  "Please enter an IP Address.");
                  }

                  return new ValidationResult(true, null);
                }
              }
        }



    2011年8月31日 1:20
  • 你可以参考:http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx#errorinfo

    一般使用IDataErrorInfo接口验证比较灵活一些.用验证类ValidationRule判断方式如下。

    <dg:DataGrid Name="dataGrid" AutoGenerateColumns="False"
    
        RowStyle="{StaticResource RowStyle}" ItemsSource="{Binding}">
    
    <strong>
    
     <dg:DataGrid.RowValidationRules>
    
      <local:RowDataInfoValidationRule ValidationStep="UpdatedValue" />
    
     </dg:DataGrid.RowValidationRules>
    
    </strong>
     <dg:DataGrid.Columns>
    
      <dg:DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
    
      <dg:DataGridTextColumn Header="Age" Binding="{Binding Path=Age}"/>
    
      <dg:DataGridTextColumn Header="Start" Binding="{Binding Path=StartTime}"/>
    
      <dg:DataGridTextColumn Header="End" Binding="{Binding Path=EndTime}"/>
    
     </dg:DataGrid.Columns>
    
    
    
    </dg:DataGrid>
    
    

     

    public class RowDataInfoValidationRule : ValidationRule
    
    {
    
     public override ValidationResult Validate(object value,
    
         CultureInfo cultureInfo)
    
     {
    
      BindingGroup group = (BindingGroup)value;
    
    
    
      StringBuilder error = null;
    
      foreach (var item in group.Items)
    
      {
    
       // aggregate errors
    
       IDataErrorInfo info = item as IDataErrorInfo;
    
       if (info != null)
    
       {
    
        if (!string.IsNullOrEmpty(info.Error))
    
        {
    
         if (error == null)
    
          error = new StringBuilder();
    
         error.Append((error.Length != 0 ? ", " : "") + info.Error);
    
        }
    
       }
    
      }
    
    
    
      if (error != null)
    
       return new ValidationResult(false, error.ToString());
    
    
    
      return ValidationResult.ValidResult;
    
     }
    
    }
    
    

     


    • 已标记为答案 xxyxxb2080 2011年8月31日 5:07
    • 取消答案标记 xxyxxb2080 2011年8月31日 5:12
    • 已标记为答案 xxyxxb2080 2011年8月31日 5:14
    • 取消答案标记 xxyxxb2080 2011年8月31日 7:07
    2011年8月31日 5:02
  • 谢谢,我再仔细看看

    2011年8月31日 5:15
  • 不好意思,我的验证类是加载控件中了。但是点击保存的时候怎么获取控件的所有错误?
    还是不太明白加了IDataErrorInfo 接口以后有什么区别;

    我的另一个思路是:在我工程里面加一个全局的变量,在验证类里面出现错误的地方,把错误信息赋值给全局变量;点击保存的时候判断全局变量是否有错误信息来检查整个界面元素的输入正确性;所以跟IDataErrorInfo 接口也没什么关系。

     

    2011年8月31日 6:01
  • 所有的错误都存在于cultureInfo无论是一个错误还是很多错误,都会通过StringBuilder 合并到一起并以,号分割。。

         error.Append((error.Length != 0 ? ", " : "") + info.Error);

     

    2011年8月31日 7:19
  • 可是点击保存按钮,或者界面初期化的时候不会执行到这句代码来;而且IDataErrorInfo info = item as IDataErrorInfo;
    Info永远是null
    2011年8月31日 8:00
  • 有代码吗,传一份我帮你看看。

    这是我原先的帖子和你遇到的问题一样,但是我是通过IDataErrorInfo 进行的验证。

    http://social.msdn.microsoft.com/Forums/zh-CN/wpfzhchs/thread/fc744500-b9c3-4d22-822b-6aa3a37a78bd

    2011年8月31日 8:46
  • 我的这个情况和你的不太一样;下面是我的代码:输入框为空的情况下弹出消息,但是问题是如果不对文本框操作,直接点击保存没有验证,麻烦帮我看看问题出在哪儿!谢谢。

     public partial class IDataErrorInfoTest : Window
        {
            ObservableDictionary<string, object> dic = new ObservableDictionary<string, object>();

            public IDataErrorInfoTest()
            {
                InitializeComponent();

                TextBox myTextBox = new TextBox();
                myTextBox.Name = "textBox1";
                int left = 74;
                int top = 19;
                myTextBox.Width = 150;
                dic.Add(myTextBox.Name, "123");
                Binding testBinding = new Binding();
                testBinding.ValidationRules.Add(new SOTCBindingValidation.IPv4ValidationRule());
                testBinding.Path = new PropertyPath("[" + myTextBox.Name + "]");
                testBinding.Source = dic;
                myTextBox.SetBinding(TextBox.TextProperty, testBinding);
                myTextBox.Margin = new Thickness(left, top, 0, 0);
               
                canvas.Children.Add(myTextBox);
            }

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                //保存验证
            }
        }

    <Window x:Class="WpfSourceOfXML.IDataErrorInfoTest"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="IDataErrorInfoTest" Height="300" Width="300">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="213*" />
                <RowDefinition Height="8*" />
                <RowDefinition Height="40*" />
            </Grid.RowDefinitions>
            <Canvas Name="canvas">
                <Label Canvas.Left="11" Canvas.Top="19" Content="Test:" Height="25" Name="label1" Width="52" />
            </Canvas>
            <Button Content="保存" Margin="204,6,0,12" Grid.Row="2" Click="Button_Click"></Button>
        </Grid>
    </Window>

     

        public class SOTCBindingValidation
        {
            public class IPv4ValidationRule : ValidationRule
            {
                public override ValidationResult Validate(object value, CultureInfo cultureInfo)
                {
                  var str = value as string;
                  if (String.IsNullOrEmpty(str))
                  {
                      MessageBox.Show("请输入值。");
                      return new ValidationResult(false, null);
                  }
                  return new ValidationResult(true, null);
                }
            }
        }


    2011年9月1日 1:42
  • 你好,

    如果你想一开始就进行一下验证,可以把ValidationRule.ValidatesOnTargetUpdated属性设为True (http://msdn.microsoft.com/en-us/library/system.windows.controls.validationrule.validatesontargetupdated.aspx).

    如果想进行整体的验证,可以用BindingGroup解决(http://msdn.microsoft.com/zh-cn/library/system.windows.data.bindinggroup.aspx)。

    MaJiXiang的例子中是因为DataGrid内部对Row有设置BindingGroup。IDataErrorInfo是和ValidationRule的作用相似的,对整体验证并没有帮助。

    如果只想在按下按钮的时候进行验证。调用BindingGroup的ValidatWithoutUpdate方法即可。(http://msdn.microsoft.com/zh-cn/library/system.windows.data.bindinggroup.validatewithoutupdate.aspx


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 xxyxxb2080 2011年9月5日 0:39
    2011年9月1日 1:50
    版主
  • 我测试了一下你的代码,你的代码缺少

       <TextBox.Text>
    
        <Binding ValidatesOnDataErrors="True" Source="{StaticResource Ip}" Path="IpV4">
    
         <Binding.ValidationRules>
    
          <local:IPv4ValiadtionRule ValidationStep="UpdatedValue"/>
    
         </Binding.ValidationRules>
    
        </Binding>
    
       </TextBox.Text>
    
    


    所以无法获取错误异常。


    2011年9月1日 3:05
  • Min Zhu,你好!

    能帮我把上面的Demo改改吗?初期的时候吧ValidatesOnTargetUpdated属性设为True,可以在初期表示的时候出现红框;点击保存按钮的时候,让其再走一遍验证的处理还是不太明白。

    2011年9月1日 3:18
  • MaJiXiang,你好;

    我界面上的控件不是在前台写死的;是后台通过xml动态加载上的;如果是因为<local:IPv4ValiadtionRule ValidationStep="UpdatedValue"/>

    这个语句的原因,我可以在后台加上:

      Binding testBinding = new Binding();
       SOTCBindingValidation.IPv4ValidationRule rule=  new SOTCBindingValidation.IPv4ValidationRule();
        rule.ValidatesOnTargetUpdated = true;
        rule.ValidationStep = ValidationStep.UpdatedValue;

    保存按钮里面做怎么处理?



    2011年9月1日 5:30
  • 你还漏了一句吧,binding.ValidationRules.Add(rule);

    既然实现了上述代码按钮判断就可以安装MINZHU版主说的那样

    如果只想在按下按钮的时候进行验证。调用BindingGroup的ValidatWithoutUpdate方法即可。(http://msdn.microsoft.com/zh-cn/library/system.windows.data.bindinggroup.validatewithoutupdate.aspx

    2011年9月1日 6:11
  • binding.ValidationRules.Add(rule);这句代码我已经加过了

     我不明白BindingGroup从哪儿获得,又在哪儿给BindingGroup赋值?

    2011年9月1日 6:55
  • 你应该仔细看一下http://msdn.microsoft.com/zh-cn/library/system.windows.data.bindinggroup.aspx示例,它跟你现在的需求完全一样。
    2011年9月1日 7:53
  • 我已经看过了;在前台写和后台写确实是有区别,我在前台加了BindGroup,并且Textbox控件是在前台定义确实没问题;但是从后台加的控件,点击保存按钮没有反应

    例如前台这样写:

     <TextBox Height="44" HorizontalAlignment="Left"
                     Margin="254,55,0,0" Name="textBox1"
                     VerticalAlignment="Top" Width="174">
              
                    <TextBox.Text>
                        <Binding Path="aaa" StringFormat="d" >
                            <Binding.ValidationRules>
                                <src:FutureDateRule ValidatesOnTargetUpdated="True"/>
                        </Binding.ValidationRules>
                        </Binding>
                    </TextBox.Text>
            </TextBox>

    然后在后台加

     BindingGroup bin = new System.Windows.Data.BindingGroup();
                grid.BindingGroup = bin;
                grid.BindingGroup.BeginEdit();

    然后点击保存按钮

     //验证并提交 
                if (grid.BindingGroup.CommitEdit())
                {
                    MessageBox.Show("Item submitted");
                    //提交成功后继续接收edit信息
                    grid.BindingGroup.BeginEdit();
                }

    确实触发验证类;

    但是把Textbox改为在后台写:

     BindingGroup bin = new System.Windows.Data.BindingGroup();
                grid.BindingGroup = bin;
                grid.BindingGroup.BeginEdit();

                TextBox myTextBox = new TextBox();
                myTextBox.Name = "textBox1";
                int left = 74;
                int top = 19;
                myTextBox.Width = 150;
                myTextBox.Height = 20;
                dic.Add(myTextBox.Name, "123");
                Binding testBinding = new Binding();
                FutureDateRule rule = new FutureDateRule();
                rule.ValidatesOnTargetUpdated = true;
                testBinding.ValidationRules.Add(rule);
                testBinding.Path = new PropertyPath("[" + myTextBox.Name + "]");
                testBinding.Source = dic;
                myTextBox.SetBinding(TextBox.TextProperty, testBinding);
                myTextBox.Margin = new Thickness(0, top, 0, 0);
                grid.Children.Add(myTextBox);

    不触发验证类,无法获取异常;



    2011年9月1日 11:07
  • 这样触发 

    this.tbox.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));

    void ValidationError(object sender, RoutedEventArgs e)

    {

    //获取异常

    this.errorSummary.Text = Validation.GetErrors(this.tbox)[0].ErrorContent.ToString();

    }

    • 已建议为答案 MaJiXiang 2011年9月1日 11:26
    • 取消建议作为答案 xxyxxb2080 2011年9月1日 12:03
    2011年9月1日 11:22
  •  BindingGroup bin = new System.Windows.Data.BindingGroup();
                grid.BindingGroup = bin;
                grid.BindingGroup.BeginEdit();

                TextBox myTextBox = new TextBox();
                myTextBox.Name = "textBox1";
                int left = 74;
                int top = 19;
                myTextBox.Width = 150;
                myTextBox.Height = 20;
                dic.Add(myTextBox.Name, "123");
                Binding testBinding = new Binding();
                FutureDateRule rule = new FutureDateRule();
                rule.ValidatesOnTargetUpdated = true;
                testBinding.ValidationRules.Add(rule);
                bin.ValidationRules.Add(rule);
                testBinding.Path = new PropertyPath("[" + myTextBox.Name + "]");
                testBinding.Source = dic;
                myTextBox.SetBinding(TextBox.TextProperty, testBinding);
                myTextBox.Margin = new Thickness(0, top, 0, 0);


                grid.Children.Add(myTextBox);

    在后台代码中加上bin.ValidationRules.Add(rule);

    能触发到验证类

    但是没法获取value的值,value的值不是我输入的值而是System.Windows.Data.BindingGroup

     

    2011年9月1日 11:22
  • //获取Value中的异常
    
      public override ValidationResult Validate(object value,
              CultureInfo cultureInfo)
      {
        BindingGroup group = (BindingGroup)value;
    
        StringBuilder error = null;
        foreach (var item in group.Items)
        {
          // aggregate errors
          IDataErrorInfo info = item as IDataErrorInfo;
          if (info != null)
          {
            if (!string.IsNullOrEmpty(info.Error))
            {
              if (error == null)
                error = new StringBuilder();
              error.Append((error.Length != 0 ? ", " : "") + info.Error);
            }
          }
        }
    
        if (error != null)
          return new ValidationResult(false, error.ToString());
    
        return ValidationResult.ValidResult;
      }
    
    2011年9月1日 13:46
  • group.Items.count一直是0;
    2011年9月2日 0:50
  • 可以使用如下代碼:

     

    public static bool IsCanSave(DependencyObject node)
            {
                // Check if dependency object was passed
                if (node != null)
                {
                    // Check if dependency object is valid.
                    // NOTE: Validation.GetHasError works for controls that have validation rules attached
                    bool isValid = !Validation.GetHasError(node);
                    if (!isValid)
                    {
                        // If the dependency object is invalid, and it can receive the focus,
                        // set the focus
                        // add check the control is disable
                        if (node is IInputElement)
                            if (((IInputElement)node).IsEnabled == true)
                            {
                                Keyboard.Focus((IInputElement)node);
                                return false;
                            }
                    }
                }
    
                // If this dependency object is valid, check all child dependency objects
                foreach (object subnode in LogicalTreeHelper.GetChildren(node))
                {
                    if (subnode is DependencyObject)
                    {
                        // If a child dependency object is invalid, return false immediately,
                        // otherwise keep checking
                        if (IsCanSave((DependencyObject)subnode) == false) return false;
                    }
                }
    
                // All dependency objects are valid
                return true;
            }
    

    直接調用IsCanSave(grid/panel/control/uielement)就行

     

    2011年9月4日 5:00