Bindings have a source and a target. The binding target is considered to be the property on which the binding is set. This property must always be backed by a dependency property. Always, always, always. This restriction is very obvious when you create a binding in code.
To try this out in SliderBindings, delete the binding on the Text property of the TextBlock. In the MainPage.xaml.cs file, you’ll need a using directive for the System.Windows.Data namespace which contains the Binding class. In the constructor after the InitializeComponent call, create an object of type Binding and set its properties:
Binding binding = new Binding();
binding.ElementName = "slider";
binding.Path = new PropertyPath("Value");
The ElementName and Path properties reference the binding source. But look at the code to target the Text property of the TextBlock:
txtblk.SetBinding(TextBlock.TextProperty, binding);
The SetBinding method is defined by FrameworkElement, and the first argument is a dependency property. That’s the target property. The target is the element on which you call SetBinding. You can alternatively set a binding on a target using the static BindingOperations.SetBinding method:
BindingOperations.SetBinding(txtblk, TextBlock.TextProperty, binding);
But you still need the dependency property. So this is yet another reason why the properties of visual
objects should be depending properties. Not only can you style those
properties, and target them with animations, but they need to be dependency properties to be targets of data bindings.
In terms of dependency property precedence, bindings are considered the same as local settings.
The BindingOperations.SetBinding method implies that you can set a binding on any dependency property. With Silverlight for Windows Phone, this is not the case. A binding target must always be a property of a FrameworkElement.
For example, you’ll notice that the Rectangle element in MainPage.xaml has a RotateTransform set to its RenderTransform property. Try targeting the Angle property with the same binding that’s set on the Text property of the TextBlock and the Width property of the Rectangle:
<RotateTransform x:Name="rotate"
Angle="{Binding ElementName=slider, Path=Value}" />
It looks fine, but it won’t work. You’ll get a XamlParseException at runtime. Angle is backed by a dependency property, all right, but RotateTransform does not derive from FrameworkElement so it can’t be a binding target. (A Binding set on the Angle property of RotateTransform works under Silverlight 4, but Silverlight for Windows Phone is mostly Silverlight 3.)
If you’re playing along, you’ll want to remove that binding on the Angle property of RotateTransform, and any code that might have been added to MainPage.xaml.cs. The Slider has its Value property initialized to 90:
<Slider Name="slider"
Value="90" . . . />
The target of the binding is the Text property of the TextBlock:
<TextBlock Name="txtblk"
Text="{Binding ElementName=slider, Path=Value}" . . . />
Let’s switch these around. Let’s initialize the Text property of the TextBlock to 90:
<TextBlock Name="txtblk"
Text="90" . . . />
And let’s make the binding target the Value property of the Slider:
<Slider Name="slider"
Value="{Binding ElementName=txtblk, Path=Text}" . . . />
At first this seems to work. The Slider thumb is initialized to its center to indicate the value of 90 it obtained from the TextBlock, and the Rectangle size is still bound to the Slider. However, when you manipulate the Slider, the Rectangle changes height but the TextBlock doesn’t change at all. The Binding object on the Slider is looking for changes in the Text property of the TextBlock, and that’s remaining fixed.
Now add a Mode setting to the binding on the Slider to indicate a two-way binding;
<Slider Name="slider"
Value="{Binding ElementName=txtblk, Path=Text, Mode=TwoWay}" . . . />
It works! The binding target is still considered to be the Value property of the Slider. Any changes to the Text property of the TextBlock will be reflected in changes to the Value property of the Slider, but any changes to the Slider will now also be reflected in the TextBlock.
You set the Mode property to a member of the BindingMode enumeration. The default Mode property is BindingMode.OneWay. Besides BindingMode.TwoWay, the only other option is BindingMode.OneTime, which only transfers data from the source to the target once.
Using this same technique, it’s possible to establish a binding with the Angle property of the RotateTransform. Let’s first restore the TextBlock to its original binding:
<TextBlock Name="txtblk"
Text="{Binding ElementName=slider, Path=Value}" . . . />
Now put a two-way binding on the Slider that references the Angle property of the RotateTransform:
<Slider Name="slider"
Value="{Binding ElementName=rotate, Path=Angle, Mode=TwoWay}" . . . />
And that works! The Rectangle element rotates as the Slider is manipulated: