SharpGIS

#GIS from a .NET developer's perspective

Dependency Property gotchas

Here’s a quick list of gotchas I’ve learnt the hard way or seen over the time while working with Dependency Properties in Silverlight and WPF (most of this applies to Attached Properties as well).
Here’s a typical dependency property defined on a class inheriting from DependencyObject:

public int SomeValue
{
    get { return (int)GetValue(SomeValueProperty); }
    set { SetValue(SomeValueProperty, value); }
}
public static readonly DependencyProperty SomeValueProperty =
    DependencyProperty.Register("SomeValue", typeof(int), typeof(ownerclass), null);
private static void OnSomeValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ownerclass obj = (ownerclass)d;
    int newValue = (int)e.NewValue;
    int oldValue = (int)e.OldValue;
} 

Naming

The naming is very important. Note ‘SomeValue’ is not only the name of the property, but the static DependencyProperty field is prefixed with the word ‘Property’, and the string in the first parameter also must match this name.

Type and default values.


Below we instead create a dependency property of type double and define a default value in PropertyMetadata to 0. See if you can spot the bug:

public static readonly DependencyProperty SomeValueProperty =
    DependencyProperty.Register("SomeValue", typeof(double), typeof(ownerclass), new PropertyMetadata(0));

The problem is very subtle, and the error you will get at runtime is not always obvious. The reason is that PropertyMetadata takes an object as parameter, and there’s no way for the debugger to know that you meant to put a double there, and it will wrongly assume Int32. At runtime you will get an exception because of this. Instead make sure you explicitly declare the default value as a double:

public static readonly DependencyProperty SomeValueProperty =
    DependencyProperty.Register("SomeValue", typeof(double), typeof(ownerclass), new PropertyMetadata(0d));

Default values are static – Beware of object references!

Don’t ever ever EVER declare a default value in a DependencyProperty that is not a value type. Since this field is static, the default value will be shared among every instance that’s using the default value.

If I were to access the property and modify its sub properties, anything using this instance would be affected.
Example: Brush property on a control. I have multiple instances of the control, but changing a subproperty on the property will affect all the controls:

public static readonly DependencyProperty MyBrushProperty =
    DependencyProperty.Register("MyBrush", typeof(SolidColorBrush), 
    typeof(ownerclass), new PropertyMetadata (new SolidColorBrush(Colors.Red))); 

. . . 

myControl.MyBrush.Color = Colors.Blue;

Instead set the default value to null. Then either set the property in the default style template (if it’s declared on a control), or set it in the constructor of your class.

Code in property setter

Often you are used to execute code in the setter of your property when a value changes like so:

public int SomeValue
{
    get { return (int)GetValue(SomeValueProperty); }
    set 
    { 
        if(value != SomeValue)
        {
            SetValue(SomeValueProperty, value); 
            UpdateValues(value);
        }
    }
}

However, if you’ve done this, you might have seen that sometimes your setter is not called, and the UpdateValues() method is never executed. The reason is that if you are binding to this property instead of just calling the setter directly, this setter will never be hit! Instead Silverlight/WPF will call SetValue(…) directly and “circumvent” your setter (this is also why the naming mentioned above is important so it can find the property).
Instead the correct way is to declare a method to call when the value changes. This is done in the PropertyMetadata instance: Also note that you do not need to check whether the value actually has changed. The changed handler will only be called if the value is actually different.

public static readonly DependencyProperty SomeValueProperty =
    DependencyProperty.Register("SomeValue", typeof(int), typeof(ownerclass), new PropertyMetadata(0, OnSomeValuePropertyChanged));
private static void OnSomeValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ownerclass obj = (ownerclass)d;
    int newValue = (int)e.NewValue;
    obj.UpdateValues(newValue);
}

Code Syntax Highlighting in Silverlight

A little while back, Jeff Wilcox wrote an awesome syntax highlighter (blog post here). It enables you to display code in Silverlight with similar syntax highlighting that we know and love from Visual Studio. This is really useful if you want to display some code samples inside your Silverlight application.

However it had one major feature missing: You couldn’t select and copy the code. And what good are code samples if you can’t do that (unless you’re the patient type who likes typing a lot). Vladimir Horbovanu had commented that he had modified the sample to be built on MVVM and added the option of selecting and even editing the text. However, this only supported C# and not VB, JS, Xaml, C++ and Xml as the original sample did, and there were a few issues with getting the text to properly align. However the “trick” he applied was simple but clever: Put a TextBox on top of the existing control, and make it transparent.

So I basically took Jeff’ awesome library, modified the template a bit, bound a TextBox with transparent text to the source code and put it on top of the existing template parts, tweaked the TextBox template to properly align and voila: The SyntaxHighlightingTextBlock is now a SyntaxHighlightingTextBox. I also added a couple of properties to the control to quickly get the selected text, set readonly state etc.

Jeff deserves most of the credit for this one, and Vladimir the rest for the neat TextBox trick. All I did was put it together, clean it up a bit and fix a couple of bugs in the highlighter. Expect to see this used in the next release of our SDK.

You can get the source here, and view the sample app here.

The library still only requires Silverlight 3, however the demo app uses Silverlight 4’ right-click feature for the context menu.

image

Update: Vlad took this sample further and improved rendering performance when editing larger amounts of code. See his updated blogpost here: http://www.vladhorby.com/blog/post/2010/11/01/code-editor-control-with-syntax-highlighting-for-silverlight-available.aspx
Isn't it great how the .NET community works together on building some useful stuff? Thanks Vlad!