views:

171

answers:

2

The code below is my current solution.

If it takes you a couple minutes to figure out what this code is doing, I hear ya.

This is an ugly mess if ever there was one. I would kill to see an alternative, (but don't let that discourage you from responding... :-). Oh jeez, I even abbreviated it (substantially) by removing the converter code, and I STILL feel dyslexic when I look at this code.

A great example of what I am trying to mimic would be the FrameworkElement.ActualWidth property. You know how the ActualWidth property is calculated and reassigned, whenever the Width property changes, or whenever the control is redrawn, or whenever else? ------

From the developer's perspective, it just looks like data-binding hard-at-work.
But ActualWidth is a read-only dependency-property. Does Microsoft really have to go through this gigantic trash-hole of code to make that work? Or is there a simpler way that utilizes the existing functionality of the data-binding system?

public class foo : FrameworkElement
{
    [ValueConversion(typeof(string), typeof(int))]
    public class fooConverter : IValueConverter
    {   public object Convert(  object value, Type targetType,
                                object parameter, CultureInfo culture)
        { ... }
        public object ConvertBack(  object value, Type targetType,
                                    object parameter, CultureInfo culture)
        { ... }
    }

    private static readonly fooConverter fooConv = new fooConverter();



    private static readonly DependencyPropertyKey ReadOnlyIntPropertyKey =
        DependencyProperty.RegisterReadOnly( "ReadOnlyInt", typeof(int),
                                             typeof(foo), null);
    public int ReadOnlyInt
    {   get { return (int)GetValue(ReadOnlyIntPropertyKey.DependencyProperty); }
    }



    public static readonly DependencyProperty ReadWriteStrProperty =
        DependencyProperty.Register( "ReadWriteStr", typeof(string), typeof(foo),
                                     new PropertyMetadata(ReadWriteStr_Changed));
    public string ReadWriteStr
    {   get { return (string)GetValue(ReadWriteStrProperty); }
        set { SetValue(ReadWriteStrProperty, value); }
    }



    private static void ReadWriteStr_Changed(   DependencyObject d,
                                            DependencyPropertyChangedEventArgs e)
    {   try
        {   if (d is foo)
            {   foo f = d as foo;
                f.SetValue( ReadOnlyIntPropertyKey,
                            fooConv.Convert(f.ReadWriteStr, typeof(int), null,
                                            CultureInfo.CurrentCulture));
            }
        }
        catch { }
    }
}
+1  A: 

It's not as bad as you suggest, IMHO...

You could get rid of the converter : IValueConverter is for bindings, you don't need it for conversions in code-behind. Apart from that, I don't see how you could make it more concise...

Thomas Levesque
Ha, fair enough. The code has to be managable at some point, right? But wouldn't this be so much nicer if we COULD just use a binding with some special parameters, and snap the converter in to do all the work? I don't have terribly high hopes, but I'm asking this question on SO simply to confirm that this is the best way to do it.
Giffyguy
Oh! In response to your first statement, I should say that I am a hardcore C++ man. .NET (even C#) has always made me queasy, because it's so restrictive in comparison. I like to have percise control over the ways everything is executed. Alas, this may be somewhat hazardous to my .NET development...
Giffyguy
+1  A: 

Unfortunately, you'll need most of what you have. The IValueConverter isn't required in this case, so you could simplify it down to just:

public class foo : FrameworkElement
{
    private static readonly DependencyPropertyKey ReadOnlyIntPropertyKey =
        DependencyProperty.RegisterReadOnly( "ReadOnlyInt", typeof(int),
                                         typeof(foo), null);
    public int ReadOnlyInt
    {
       get { return (int)GetValue(ReadOnlyIntPropertyKey.DependencyProperty); }
    }

    public static readonly DependencyProperty ReadWriteStrProperty =
        DependencyProperty.Register( "ReadWriteStr", typeof(string), typeof(foo),
                                 new PropertyMetadata(ReadWriteStr_Changed));

    public string ReadWriteStr
    {
       get { return (string)GetValue(ReadWriteStrProperty); }
        set { SetValue(ReadWriteStrProperty, value); }
    }

    private static void ReadWriteStr_Changed(DependencyObject d,
                                        DependencyPropertyChangedEventArgs e)
    {
         foo f = d as foo;
         if (f != null)
         {
              int iVal;
              if (int.TryParse(f.ReadWriteStr, out iVal))
                  f.SetValue( ReadOnlyIntPropertyKey, iVal);
         }
    }
}
Reed Copsey
I'm used to seeing converters, because they are all over the place in the bindings in my app. I put it in with the small hope that a binding could be used here in the place of a PropertyChangedCallback. I guess this is just how it is ...
Giffyguy
The one thing to remember - one callback can handle ALL of your read only properties, though. You don't need to have one per property, so it's really not too bad.
Reed Copsey