Silverlight supports data binding, but currently there is a lack of samples explaining some of the nicer concepts, plus some of the things are not as you might expect.
Data binding in Silverlight is through the {Binding <Path>} syntax, for example to bind a TextBox's Text property to the Value property of some class you would use
<TextBox Text="{Binding Value}" />
The catch is that this is a one way binding, if you change the Text in the TextBox the Age property doesn't get updated...
The solution is simple, you need to set the Mode property of the Binding object to TwoWay like this:
<TextBox Text="{Binding Value, Mode=TwoWay}" />
Now modifying the Text property will modify the Value property (and vice versa).
Next on my agenda is data conversion. You can do this by using a class that implement the IValueConverter interface, for example:
public class DoubleToBrushConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { string v = (value ?? "0").ToString(); double cutoff = parameter == null ? 30 : double.Parse( parameter.ToString() ); if (double.Parse(v) < cutoff) return new SolidColorBrush(Colors.Green); else return new SolidColorBrush(Colors.Red); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
This class will convert the value to a brush, nice if you want to show the user that an invalid or unusual value was entered. You can use this as follows:
<TextBox Text="{Binding Value, Mode=TwoWay}" Background="{Binding Value, Converter={StaticResource converter}, ConverterParameter=40}" />
The ConverterParameter will get passed into the Convert method as the parameter parameter.
Please note that we don't need to implement the ConvertBack method of the IValueConverter interface because the user will not be able to change the background color.
When the value goes above 40 the background turns red.
Last thing is the Source property of the Binding element. With this you can point to some object on your Page, stored as a resource:
<TextBox Text="{Binding Value,
Mode=TwoWay,
Source={StaticResource someObject}}" />
This of course opens up using Element binding, which means binding to elements of your page to each other. The technique I propose is using some temporary object and binding the controls to this object.
For example, to bind three controls (two textboxes and one slider) to each other use following markup:
<TextBox Text="{Binding Value, Mode=TwoWay, Source={StaticResource someObject}}" /> <TextBox Text="{Binding Value, Mode=TwoWay, Source={StaticResource someObject}}" Background="{Binding Value, Source={StaticResource someObject}, Converter={StaticResource converter}, ConverterParameter=40}" /> <Slider x:Name="theSlider" Minimum="0" Maximum="100" SmallChange="1" LargeChange="10" Value="{Binding Value, Mode=TwoWay, Source={StaticResource someObject}}" />
Each binding refers to the same Source, which I've declared on top of the page resources:
<UserControl.Resources> <u:DoubleToBrushConverter x:Key="converter" /> <u:ElementBinding x:Key="someObject" Value="66" /> </UserControl.Resources>
The DoubleToBrushConverter class is the one on top, the ElementBinding class looks like this:
public class ElementBinding : INotifyPropertyChanged { double val; public double Value { get { return val; } set { val = value; OnPropertyChanged("Value"); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propName)); } }
The class implements the standard INotifyPropertyChanged interface to support databinding.
A demo project containing this sample can be found here.