In my previous posts about binding in code behind with WPF, I talked about my helper class that allowed me to quickly create a dependency property within any class and use a number of static functions to quickly bind dependency properties in code behind. So when I took a look at the binding capabilities in Silverlight 2.0 I was disappointed to find out that much of the binding had been stripped out. In fact there was almost nothing from my user class that I could use in Silverlight 2.0 because of the exclusion of the class BindingOperations. So how does one bind in code behind in Silverlight 2.0? First I had to get my head around what was stripped out from WPF and how to work around the exclusion of BindingOperations. BindingOperations was how one actually did the binding with the call to BindingOperations.SetBinding(). Where did this function go in Silverlight 2.0? The answer was that it got moved to the FrameworkElement object who owns the target dependency property. That’s not so bad I thought, but I was wrong. I discovered that in Silverlight 2.0 you can’t bind directly between two UI elements. For instance, if you have a slider and a progressbar and you need to bind the Max properties together. You are out of luck, Silverlight 2.0 will not allow those two dependency properties to be directly bound. Why??? That had to have been an oversight. Searching around for the reason and what to do about this I came across this post by David Justice. This guy even came up with his own binding helper class. To solve the binding problem with the two Max properties, it turns out that you have to create a intermediary property that both of the UI properties can be bound to. That’s kind of ugly, but it does work. In David’s post the binding was all done in XAML with the helper class in the resources, but I wanted to do all of my work in code behind. I build upon David’s helper class by adding a couple of static functions for binding, much like what I did in my WPF helper class.
public class BindingHelper : INotifyPropertyChanged
{
public static void SetBinding(BindingHelper bindingHelper, FrameworkElement target,
DependencyProperty dp)
{
SetBinding(bindingHelper, target, dp, null);
}
public static void SetBinding(BindingHelper bindingHelper, FrameworkElement target,
DependencyProperty dp, BindingMode? mode)
{
Binding binding = new Binding("Value");
binding.Source = bindingHelper;
if (mode.HasValue) binding.Mode = mode.Value;
target.SetBinding(dp, binding);
}
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
}
Looking at my static functions you can see that code behind binding in Silverlight 2.0 is much like WPF, except for where the SetBinding function is located. As you can see you actually call it from the target FrameworkElement object. Because the helper class is not a FrameworkElement you can’t bind it as a target, it must be the source in your binding. This must be considered when you layout your design for dependency property binding. To actually get a value from the UI to the helper class you have to set the BindingMode to TwoWay. Again, it’s not pretty.
I then decided to try to duplicate my previous WPF binding example in Silverlight 2.0. So I needed a couple of sliders and a progressbar.
<UserControl x:Class="slBindingTest.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Slider Name="slider1" Margin="20,20" VerticalAlignment="Top" HorizontalAlignment="Left"
Width="200" Maximum="100" Minimum="0" Height="20" />
<ProgressBar Name="progressBar" Margin="20,70" VerticalAlignment="Top" HorizontalAlignment="Left"
Width="200" Maximum="100" Minimum="0" Height="20" />
<Slider Name="slider2" Margin="20,120" VerticalAlignment="Top" HorizontalAlignment="Left"
Width="200" Maximum="100" Minimum="0" Height="20" />
Grid>
UserControl>
Now I needed to add some code behind to use the modified helper class to bind the values of the sliders and the progress bar.
void Page_Loaded(object sender, RoutedEventArgs e)
{
bindingValue = new BindingHelper();
BindingHelper.SetBinding(bindingValue, slider1, Slider.ValueProperty, BindingMode.TwoWay);
BindingHelper.SetBinding(bindingValue, slider2, Slider.ValueProperty, BindingMode.TwoWay);
BindingHelper.SetBinding(bindingValue, progressBar, ProgressBar.ValueProperty, BindingMode.OneWay);
}
That’s it. Run this in silverlight 2.0 and we are binded. Just as in my WPF example if you change either of the sliders, you will see that the values of the other slider and the progressbar are updated.
In the latest Silverlight release 3.0, the problem of binding directly between UI element dependency properties has been fixed. That was great to see. I’ll explore that in future posts.