I Can't Believe That Worked

Code and Ideas, minus the profanity (the one language all developers know)

Silverlight 2 XAML Binding and Custom / Core Dependency Properties

Lately, I have been working in Silverlight 2 quite a bit.  I have been infused with inspiration from the Chicago PhizzPop Design Challenge.  I'm waiting for the pictures and vids from a couple people to be served.  I will be linking them into the blog.  For the time being, I have been hacking away at some of my own interests.

I ran into some interesting issues with the SL 2 binding.  I don't think these are new.  There have been several posts about them in the past, but I wanted to dig into them for myself, and see what reflector had to say about it.

Update:  I was completely wrong... "I will take SWORDS for 500 Alex"

Thankfully, a very friendly and knowledgeable Justin-Josef Angel helped me out with the issue and learned me 'bout some silverlight.  Thank you very much Justin!  Ok, so what I was trying to do was a little boneheaded  (we all know pride tastes really bad)...  Really, the way around the issue, as Justin pointed out, is to handle the PropertyChangedCallback on the dependency property rather than trying to place logic in the setter of the CLR Property which fronts the DependencyProperty.  I am providing below the updated GlassButton class with the changes suggested.

We can all be pretty damn dumb from time to time.  All we can hope is to try to learn from our mistakes, so we can be just that little bit better the next day.  Anything you read below with a line struck through it, is null and void (aka dumbness).  I hope this helps everyone out :).

public class GlassButton : Button

    {

        public static readonly DependencyProperty _radiusProperty = DependencyProperty.Register("Radius",

                                                                                                typeof (double),

                                                                                                typeof (GlassButton),

                                                                                                new PropertyMetadata(

                                                                                                    new PropertyChangedCallback

                                                                                                        (RadiusCallback)));

 

 

        public double Radius

        {

            get { return (double) this.GetValue(_radiusProperty); }

            set { this.SetValue(_radiusProperty, value); }

        }

 

        private static void RadiusCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)

        {

            var value = (double) e.NewValue;

            if (value > 0)

            {

                ((FrameworkElement) d).RenderTransform = new ScaleTransform {ScaleX = value/26, ScaleY = value/26};

            }

        }

    }

 

The basic scenario is as follows:  I have done quite a bit of WPF programming in the past (since back when it was WinFx).  I feel pretty damn good about the bindings in WPF, and I feel like I have wrapped my head around binding and dependency properties pretty well.  So, I thought when I decided to write Silverlight 2 apps rather than WPF apps, it would be a very similar feeling.  The feeling was abruptly interrupted by the evilness of the ElementName Binding param.  For those of you who have spent time writing WPF apps, you will know the joy of binding element properties to each other and having no problems.  It's easy to take such things for granted.

I understand you have to trim down the size of the download package for SL, and I am perfectly groovy with that fact.  The issue I have with it, is that there is no recourse for a developer to step outside of those bounds.  Meaning, I would like to have my CustomDependencyProperties be able to take part in XAML binding, the same way CoreDependencyProperties take part in binding.  Below, I'm going to outline some code to illustrate my issue.  Mind you this code is not at all cool.  It just is there to elucidate my point.  If you want cool code, you can look to my boy Brownie, or some other person in a better mood.

XAML:

<UserControl x:Class="Test.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   xmlns:Test="clr-namespace:Test"

   Width="400" Height="300">

    <Canvas>

        <Canvas.Resources>

            <Test:BindingHelper x:Key="bindingHelper"/>

        </Canvas.Resources>

        <Test:GlassButton x:Name="glass" Content="{Binding Value, Source={StaticResource bindingHelper}}"

                         Radius="{Binding Value, Source={StaticResource bindingHelper}}" Canvas.Top="10"/>

        <Slider Value="{Binding Value, Source={StaticResource bindingHelper}, Mode=TwoWay}"

               Width="100" Maximum="100" Minimum="0" Height="20"/>

    </Canvas>

</UserControl>

BindingHelper:

#region

 

using System.ComponentModel;

 

#endregion

 

namespace Test

{

    public class BindingHelper : INotifyPropertyChanged

    {

        private double value;

 

        public double Value

        {

            get { return this.value; }

            set

            {

                this.value = value;

                if (this.PropertyChanged != null)

                {

                    this.PropertyChanged(this, new PropertyChangedEventArgs("Value"));

                }

            }

        }

 

        #region INotifyPropertyChanged Members

 

        public event PropertyChangedEventHandler PropertyChanged;

 

        #endregion

    }

}

GlassButton:

#region

 

using System.Windows;

using System.Windows.Controls;

using System.Windows.Media;

 

#endregion

 

namespace Test

{

    public class GlassButton : Button

    {

        public static readonly DependencyProperty _radiusProperty = DependencyProperty.Register("Radius", typeof (double),

                                                                                  typeof (GlassButton), null);

 

 

        public double Radius

        {

            get { return (double)GetValue(_radiusProperty); }

            set

            {

                if (value > 0)

                {

                    this.RenderTransform = new ScaleTransform {ScaleX = value/26, ScaleY = value/26};

                    this.SetValue(_radiusProperty, value);

                }

            }

        }

    }

}

Check out the code if you will.  It's in a nice little sln zipped up, with a bow on top.  Cheers!  CODE ZIPPED UP

Twitter: @DavidJustice

kick it on DotNetKicks.com

Comments

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# November 23, 2008 11:06 AM

Justin-Josef Angel said:

Hi David, I'll try to go easy on you because I like you personally :)

However, just for the sake of anyone reading this - what you said is completely wrong.

Still loving you David, but you missed this one big time.

The only thing that doesn't get called in this binding is the custom CLR property Radius Setter. However, you still get this nifty callback method which is the *only* thing you should use for custom DP change notifications.

Here's how you *should* have used the custom DP change notifications:

(pretty & readable version at http://pastebin.com/m62b2000b)

   public class GlassButton : Button

   {

       public static readonly DependencyProperty _radiusProperty = DependencyProperty.Register("Radius", typeof(double),

                                                                                 typeof(GlassButton), new PropertyMetadata(RadiusCallBack));

       private static void RadiusCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)

       {

           GlassButton sender = (GlassButton) d;

           int value = Convert.ToInt32(e.NewValue);

           if (value > 0)

               sender.RenderTransform = new ScaleTransform { ScaleX = value / 26, ScaleY = value / 26 };

       }

       public double Radius

       {

           get { return (double)GetValue(_radiusProperty); }

           set { this.SetValue(_radiusProperty, value); }

       }

   }

-- Justin

(remember, it's all from love :))

# November 23, 2008 9:58 PM

Community Blogs said:

In this issue: Hannes Preishuber, David Justice, Dan Wahlin, Terence Tsang, and Chris Carper. From SilverlightCream

# November 24, 2008 8:06 AM

2008 November 25 - Links for today « My (almost) Daily Links said:

Pingback from  2008 November 25 - Links for today « My (almost) Daily Links

# November 25, 2008 1:33 AM

jason kenny said:

Interesting, but usual =)

# January 16, 2009 9:43 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)