Custom DependencyProperties and “Auto”

by Christoph Menge in Software

While implementing a little custom control (a radial panel, actually – stay tuned what it’s good for…), I stumbled across a little problem when trying to add automatic behaviour.

Many built-in WPF Controls such as Canvas or Panel allow something like

Width="Auto"

Now, for my control I need something that accepts

AngleSpacing="Auto"
AngleSpacing="<double>"

Of course, accomplishing that is very simple, but it took me some time to find it on MSDN:

In addition to acceptable Double values, this property can also be Double.NaN. This is how you specify auto sizing behavior in code. In XAML you set the value to the string “Auto” (case insensitive) to enable the auto sizing behavior. Auto sizing behavior implies that the element will fill the height available to it. Note however that specific controls frequently supply default values through their default theme styles that will disable the auto sizing behavior unless it is specifically re-enabled.

So, the solution simply is to apply the TypeConverterAttribute as follows:

[TypeConverterAttribute(typeof(LengthConverter))]
public double AngleSpacing
{
    get { return (double)GetValue(AngleSpacingProperty); }
    set { SetValue(AngleSpacingProperty, value); }
}
public static readonly DependencyProperty AngleSpacingProperty =
    DependencyProperty.Register("AngleSpacing",
                                  typeof(double),
                                  typeof(CircularPanel),
                                  new FrameworkPropertyMetadata(45d,
                                  FrameworkPropertyMetadataOptions.AffectsArrange));

This will, however, leave us with a length converter (which is built mainly for Conversion of “pt”, “px”, etc.). There are quite a lot of type coverters available already. For a list, see http://msdn2.microsoft.com/en-us/library/system.componentmodel.typeconverter.aspx.  

In my case, I need a custom TypeConverter, which is really simple:

public class DoubleAutoConverter : TypeConverter
{
  public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  {
    if (sourceType == typeof(string) || sourceType == typeof(double))
    {
      return true;
    }

    return base.CanConvertFrom(context, sourceType);
  }

  // Overrides the ConvertFrom method of TypeConverter.
  public override object ConvertFrom(ITypeDescriptorContext context,
     CultureInfo culture, object value)
  {
    if (value is string)
    {
      double dValue;

      if (String.Compare((string)value, "auto", true) == 0)
      {
        dValue = Double.NaN;
      }
      else
      {
        // Don't catch the exception
        dValue = Double.Parse((string)value);
      }

      return dValue;
    }

    // No need to handle the trivial case manually:
    return base.ConvertFrom(context, culture, value);
  }

  public override object ConvertTo(ITypeDescriptorContext context,
     CultureInfo culture, object value, Type destinationType)
  {
    return base.ConvertTo(context, culture, value, destinationType);
  }
}

Now, when the user specifies auto, the property will be set to Double.NaN and can be handled by the control… hopefully

Post to Twitter Post to Delicious Post to Digg Post to Facebook

Related posts:

  1. A very simple profiler
  2. A MenuKiller Control – Draft

Tags: , , ,

← Previous

Next →

Leave a Comment