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?
views:
2868answers:
5This 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);
}
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.
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.
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.
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.