Silverlight, WPF and .NET Subscribe via RSS
Photo of Alan Cobb
About me:   I'm a Silverlight 4, WPF (Windows Presentation Foundation) and .NET programmer based in Northern California, USA.   See more about the Silverlight presentations I have been giving here.

I'm currently available for work.  Send me an email at the address here and we can talk about your project. 
Changing Silverlight properties dynamically with a "binding-relay" object
By: Alan Cobb Date: 2008-Jul-17 14:39

What if you want the user of your Silverlight app to be able to change some properties of your UI dynamically on-the-fly?  For example, it would be nice to let your user set the FontSize to their liking at runtime and have that new size used by all controls immediately.

One way to do that is with data binding and a shared "app-global" "binding-relay" object.  The graphic below shows the UI of this sample app and how its elements are indirectly connected with data binding via a "binding-relay" object.  This general technique has been described by other people as part of larger articles (see for example, here and here [both links are slow]), but here I want to emphasize just this one technique.  Although it has some disadvantages, it's a useful pattern to have in your toolbox.

My sample app is split into two sections.  The group of "controller" elements in the upper half is used to dynamically change the properties of the "controlled" TextBlocks in the lower half.  The graphic below shows the UI of this sample app and how its elements are indirectly connected with data binding.

Annotated screen capture of sample app demoing Silverlight data binding using a binding-relay object

Live copy of this sample app (SL2B2 version)

Sample source code as zipped VS2008 solution
(After you unzip and rebuild it, remember to again set the HTML page in the web project as the Start Page before you run it with F5.)

How it works:
We start by creating a custom class that exposes the global properties we want to support.  For example, "double dFontSize".  In this sample the class is called CBindingRelayClass_ApplicationWideSettings.  We create a single shared instance of that class by instantiating it in the App.Resources section of our App.xaml.  Now multiple elements anywhere in our application can bind their FontSize properties as targets to the dFontSize source property on the global object.  This class must support the INotifyPropertyChanged interface.  That's how the binding system is alerted when one of our global properties is changed.  Then the binding system "relays" that change out to all the bound targets of that global source property.  That's why I call it a "binding-relay" object.

We drive changes to the global dFontSize property with a Slider.  The Slider is TwoWay bound back to the global binding source object.  The binding mode for the Slider must be TwoWay in order for it to drive the value of the dFontSize property (changes flowing from target back to source).  Normal OneWay binding only moves changes in the other direction, from binding source to target.

So those are the basic "tricks" behind this technique.

More implementation details:
It's easy enough to use TwoWay binding to make the Slider drive a property like dFontSize because it has the simple type double.  But what about a type like FontFamily?  In this sample I use a ListBox to choose the FontFamily.  But instead of TwoWay binding, I fall back on an "old school" event handler.  In the ListBox.SelectionChanged event handler I "manually" instantiate a new FontFamily object based on the selected line in the ListBox and assign it to the oFontFamily property on the global "binding relay" object.

What about the Slider driving the oSolidColorBrush property on the global object?  There I also go "old school" rather than using TwoWay binding.  In the Slider.ValueChanged event handler I "manually" translate the Slider Value (which ranges from 0x000000 to 0xffffff) into an RGB color, use that to instantiate a new SolidColorBrush and finally assign that to the global oSolidColorBrush property.

In theory we could have used TwoWay binding to drive the values of both these more complex properties.  That would require writing value converter classes that implement IValueConverter.  For example, we should be able to write a value converter that translates back and forth between the types double and SolidColorBrush.  My preliminary experiments under SL2B2 with TwoWay binding using value converters for more complex types didn't work, so I haven't shown that here.

Although using a "binding-relay" object does let you dynamically change properties in real-time, it also has some disadvantages.  One burden is just that you need to define and instantiate the binding-relay object somewhere.  In contrast to the current Silverlight version, WPF's binding system allows you to directly bind one element to another, without needing a "relay" object in between (See for example).  So in WPF you could directly bind the FontSize property of one element to the output of a Slider control.  Another drawback is the extra binding XAML you must add to every control that consumes the "dynamic property".   For example:  FontSize="{Binding dFontSize}".

New "property value inheritance" of font properties in Silverlight:
This technique's ability to dynamically control the font properties of many target elements simultaneously seemed a bit more impressive before SL2 Beta 2.  But now SL2B2 has introduced more "property value inheritance" to Silverlight, something which WPF already broadly supports.  Most of the font-related properties (like FontSize and FontFamily) have been moved to the Control class in SL2B2.  Now those values are "inherited" by the child elements inside a given control.  This means you can set the FontSize and FontFamily once on a UserControl and those values will cascade (like in CSS) down to the child elements.  To demonstrate that you can add these bound properties to the XAML that defines the Page UserControl:

    FontSize="{Binding dFontSize}"
    FontFamily="{Binding oFontFamily}"

After that change when you vary the FontSize Slider, the text size changes everywhere on the Page, not just in the lower half.  We are still using the "binding-relay" object, but now it is unnecessary to duplicate the same binding XAML on every target element.

Alan Cobb

Comments [2]  |  data binding | Silverlight #  
Copyright 2014 Alan Cobb:    Subscribe: Subscribe via RSS
Theme by Alan Cobb, based on dasBlog calmBlue.
newtelligence dasBlog 2.3.9074.18820
Page rendered: 2014-Apr-19 07:40 CA, USA Time
dasBlog logo
Admin Login