Sunday, April 15, 2007

Converter and Validator in one place

Today, Doug asks about strange behavior with Binding Validation, while using custom converters. Follow XAML and C# code for his question:

 

<StackPanel>
    <StackPanel.DataContext>
      <x:Array Type="s:Int32" xmlns:s="clr-namespace:System;assembly=mscorlib">
        <s:Int32>0</s:Int32>
        <s:Int32>1</s:Int32>
      </x:Array>
    </StackPanel.DataContext>
    <TextBox Margin="3">
      <TextBox.Text>
        <Binding Path="[0]">
          <Binding.ValidationRules>
            <ExceptionValidationRule />
          </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>
    <TextBox Margin="3">
      <TextBox.Text>
        <Binding Path="[1]">
          <Binding.Converter>
            <local:MyInt32Converter xmlns:local="clr-namespace:myNamespace" />
          </Binding.Converter>
          <Binding.ValidationRules>
            <ExceptionValidationRule />
          </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>
  </StackPanel>
 
 

public class MyInt32Converter : IValueConverter
    {
        public object Convert(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            return value.ToString();
        }
 
        public object ConvertBack(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            return Int32.Parse(value.ToString());
        }
 
    }

Compile and run it. Then change value to something bad (e.g. "aaa") in first textbox - the validator will be fired and we'll get red border in our textbox. Then change the value of the second textbox - you'll get exception. Why this?


The answer is really simple - the sequence of binding is straight forward - get,convert,validate result. So, how to get this work with custom converters? Just convert it to validator. Following code in this converter will check and validate input value first, then, if the input is valid, convert and return results.


 



    [ValueConversion(typeof(String), typeof(Int32))]
    public class MyInt32Converter : ValidationRule, IValueConverter
    {
        public object Convert(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            return value.ToString();
        }
 
        public object ConvertBack(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            if (this.Validate(value, culture) == ValidationResult.ValidResult)
            {
                return Int32.Parse(value.ToString());
            }
            return value;
        }
 
 
 
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            int i=0;
            return new ValidationResult(Int32.TryParse(value.ToString(),out i),"The string is in incorrect format");
        }
    }

Have a nice day.

No comments: