views:

2868

answers:

5

I have a control which inherits from (you guessed it) Control. I want to receive a notification whenever the FontSize or Style properties are changed. In WPF, I would do that by calling DependencyProperty.OverrideMetadata(). Of course, useful things like that have no place in Silverlight. So, how might one receive those kinds of notifications?

+1  A: 

This is what I always use (haven't tested it on SL though, just on WPF):

    /// <summary>
    /// This method registers a callback on a dependency object to be called
    /// when the value of the DP changes.
    /// </summary>
    /// <param name="owner">The owning object.</param>
    /// <param name="property">The DependencyProperty to watch.</param>
    /// <param name="handler">The action to call out when the DP changes.</param>
    public static void RegisterDepPropCallback(object owner, DependencyProperty property, EventHandler handler)
    {
        // FIXME: We could implement this as an extension, but let's not get
        // too Ruby-like
        var dpd = DependencyPropertyDescriptor.FromProperty(property, owner.GetType());
        dpd.AddValueChanged(owner, handler);
    }
Paul Betts
I'm pretty sure DependencyPropertyDescrtiptors are mythical beasts in Silverlight, unfortunately.
MojoFilter
DependencyPropertyDescriptor is not supported by Silverlight 2 or 3
markti
A: 

You cannot externally listen to dependency property changed notifications.

You can access the Dependency Property Metadata with the following line of code:

PropertyMetadata metaData = Control.ActualHeightProperty.GetMetadata(typeof(Control));

However, the only public member that is exposed is "DefaultValue".

There are a multitude of ways to do this in WPF. But they are currently not supported by Silverlight 2 or 3.

markti
A: 

The only solution I see is to listen to the LayoutUpdated event - yes, I know it is called a lot. Note however that in some cases it won't be called even though FontSize or Style has changed.

Vlad Filyakov
+4  A: 

It's a rather disgusting hack, but you could use a two-way binding to simulate this.

i.e. have something like:

public class FontSizeListener {
    public double FontSize {
        get { return fontSize; }
        set { fontSize = value; OnFontSizeChanged (this, EventArgs.Empty); }
    }

    public event EventHandler FontSizeChanged;

    void OnFontSizeChanged (object sender, EventArgs e) {
      if (FontSizeChanged != null) FontSizeChanged (sender, e);
    }
}

then create the binding like:

<Canvas>
  <Canvas.Resources>
     <FontSizeListener x:Key="listener" />
  </Canvas.Resources>

  <MyControlSubclass FontSize="{Binding Mode=TwoWay, Source={StaticResource listener}, Path=FontSize}" />
</Canvas>

then hook up to the listener's event in your control subclass.

toshok
+5  A: 

I think here is a better way. Still need to see the pros and Cons.

 /// Listen for change of the dependency property
    public void RegisterForNotification(string propertyName, FrameworkElement element, PropertyChangedCallback callback)
    {

        //Bind to a depedency property
        Binding b = new Binding(propertyName) { Source = element };
        var prop = System.Windows.DependencyProperty.RegisterAttached(
            "ListenAttached"+propertyName,
            typeof(object),
            typeof(UserControl),
            new System.Windows.PropertyMetadata(callback));

        element.SetBinding(prop, b);
    }

And now, you can call RegisterForNotification to register for a change notification of a property of an element, like .

RegisterForNotification("Text", this.txtMain,(d,e)=>MessageBox.Show("Text changed"));
            RegisterForNotification("Value", this.sliderMain, (d, e) => MessageBox.Show("Value changed"));

See my post here on the same http://amazedsaint.blogspot.com/2009/12/silverlight-listening-to-dependency.html

Using Silverlight 4.0 beta.

amazedsaint
I like that this is a nicer way of wrapping up that ugly binding, but that is an awfully heavy way to get property change notifications.
MojoFilter
As long as we need to do it entirely from the code, I guess we don't have another option till we get the DependencyPropertyDescriptor in Silverlight from MS
amazedsaint