none
TextBox input validation

    Question

  • How can I validate input for my textboxes? For example I have an application where I want to input several numbers in the textboxes. The primary validation constraint is that I want the user to be able to input only valid real numbers. Some of the textboxes should contain only positive real numbers. Also I want to be able to do comparisons between the different values (for example I have a minimum speed textbox, and maximum speed textbox, so there's one more rule here: min <= max). Also, if the user is currently editing a textbox, he should be able to cancel the modifications, by pressing escape. How can I do all these with Avalon/WPF?


    Thanks in advance,
    Cosmin.
    Sunday, April 23, 2006 1:27 PM

Answers

  • I think you should look into ValidationRule.

    Search this forum or the net.

    Best regards,
      Thomas Andersen

     

    Monday, April 24, 2006 6:39 AM

All replies

  • I think you should look into ValidationRule.

    Search this forum or the net.

    Best regards,
      Thomas Andersen

     

    Monday, April 24, 2006 6:39 AM
  • I am having some problems doing this.

    1. I have a 'motor' private field of type 'Motor' in the code behind file. I want to bind to its 'Resolution' property (Motor.Resolution). How do I do this? I've tried setting a static resource like: <l:Motor x:Name="motor" x:Key="motorkey" /> and then use the key in the XAML file. But it doesn't work, it's like it has two Motor objects (the private field, and the static resource). How can I bind to it (the private field)?

    2. I have two textboxes, for MinSpeed and MaxSpeed. Logically, MinSpeed should not be greater than MaxSpeed. How does the validation rule mechanism come in handy here?

    Thanks,
    Cosmin.
    Monday, April 24, 2006 8:48 AM
  • You can do something like this (note; you need to tweak it, this is only for demonstration):

    XAML:
    <Window x:Class="WindowsApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WindowsApplication1"
        Title="WindowsApplication1" Height="300" Width="300"
        Name="myWindow"
        >
      <StackPanel DataContext="{Binding ElementName=myWindow}">
        <TextBox Text="{Binding Path=Motor.Resolution}" />
        <TextBox Name="tbMin">
          <TextBox.Text>
            <Binding Path="Motor.Min">
              <Binding.ValidationRules>
                <local:ValidateMin />
              </Binding.ValidationRules>
            </Binding>
          </TextBox.Text>
        </TextBox>
        <TextBox Text="{Binding Path=Motor.Max}" />
      </StackPanel>
    </Window>


    Codebehind:
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Globalization;


    namespace WindowsApplication1
    {
     /// <summary>
     /// Interaction logic for Window1.xaml
     /// </summary>
     public partial class Window1 : Window
     {
      private Motor motor = new Motor();

      public Motor Motor
      {
       get { return motor; }
       set { motor = value; }
      }

      public Window1()
      {
       InitializeComponent();
      }

      protected override void OnInitialized(EventArgs e)
      {
       base.OnInitialized(e);
       (this.tbMin.GetBindingExpression(TextBox.TextProperty).ParentBinding.ValidationRules[0] as ValidateMin).Motor = this.motor;
      }

     }

     public class Motor
     {
      private double resolution;
      private double min;
      private double max;

      public double Resolution
      {
       get { return resolution; }
       set { resolution = value; }
      }

      public double Min
      {
       get { return min; }
       set { min = value; }
      }

      public double Max
      {
       get { return max; }
       set { max = value; }
      }
     }

     public class ValidateMin : ValidationRule
     {
      private Motor motor;

      public Motor Motor
      {
       get { return motor; }
       set { motor = value; }
      }

      public ValidateMin()
      {
      }

      public override ValidationResult Validate(object value, CultureInfo cultureInfo)
      {
       if (Convert.ToDouble(value) > this.Motor.Max)
        return new ValidationResult(false, "Min cannot be bigger that max");
       else
        return new ValidationResult(true, null);
      }
     }

    }

    This is however an ugly line:
     (this.tbMin.GetBindingExpression(TextBox.TextProperty).ParentBinding.ValidationRules[0] as ValidateMin).Motor = this.motor;

    Does anyone know how to pass the value through XAML instead??


     

    Monday, April 24, 2006 9:51 AM
  • Thanks for the consistent reply. This looks like something I can relate to. :)

    Is it really necessary to have the motor exposed as a public property? In my class I have it as a private member field, and there's no other reason for exposing this, other than this.
    Monday, April 24, 2006 10:12 AM
  • Could this sample code solve the ugly line you were talking about?

    XAML Snippet:

              <Binding.ValidationRules>
                <c:DoubleRangeRule Min="0.0" Max="90.0"/>
              </Binding.ValidationRules>


    CODE:

        class DoubleRangeRule : ValidationRule
        {
            private double mMin;
            private double mMax;

            public DoubleRangeRule()
            {
            }

            public double Min
            {
                get { return mMin; }
                set { mMin = value; }
            }

            public double Max
            {
                get { return mMax; }
                set { mMax = value; }
            }

            public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
            {
                double val = 0;

                try
                {
                    if (((string)value).Length > 0)
                        val = double.Parse((string)value);
                }
                catch (Exception e)
                {
                    return new ValidationResult(false, "Illegal characters or " + e.Message);
                }

                if ((val < mMin) || (val > mMax))
                {
                    return new ValidationResult(false,
                      "Please enter a real number in the range: " + mMin + " - " + mMax + ".");
                }

                return new ValidationResult(true, null);
            }
        }
    Monday, April 24, 2006 10:18 AM
  • Yes <c:DoubleRangeRule Min="0.0" Max="90.0"/> works fine, but then the values are hardcoded, I thought you wanted them to be dynamic.
    I was thinking something in the line of: <local:ValidateMin Motor="Motor">. But I can't get it to work.

    Yes I think that Motor has to be public.

     

    Monday, April 24, 2006 10:29 AM
  • Hmm... actually this was one of the original problems I had, not being able to set something defined in code-behind throught XAML:

    how to get Motor? :
    CodeBehind[Motor] --------------> XAML

    how to set ValidationRule parameter? :
    XAML ------------>CodeBehind[ValidationRule]

    If we can find this, we solved both problems.
    Monday, April 24, 2006 10:29 AM
  • Here's what I found while searching the net:

    "Binding Sources

    Up to this point, we've used another control as the source for all of our binding examples. In most XAML-based projects, however, you will be binding to sources other than other controls. The key to most data binding is the Source property. In the previous examples, we are using the ElementName property, which is used to bind to a control, instead of using the Source property. For most applications, you will want to bind to more significant sources, such as XML or .NET objects. XAML supports this with its data provider objects. There are two types of data providers built into XAML: ObjectDataProvider and XmlDataProvider. The ObjectDataProvider is used for binding to and from .NET objects, and, not surprisingly, the XmlDataProvider is used to bind to and from XML fragments and documents. You can specify a data provider in the resources section of any XAML container."

    Taken from:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnlong/html/WPFDataBinding_Pt1.asp

    Still, the class isn't documented.
    Monday, April 24, 2006 10:41 AM
  • Taken from the same document:

    "If you want to bind to objects that already exist at runtime or static objects, you cannot use XAML syntax to do it."

    This kindof lets me down. The documentation seems old, I wonder if it still applies...
    Monday, April 24, 2006 10:54 AM
  • That dosn't apply, as you can see my example works fine.

     

    Monday, April 24, 2006 10:56 AM
  • Yes, but you don't do it in XAML. I am talking about the ugly line.
    Monday, April 24, 2006 10:58 AM