The two binding services you’ve
seen so far simply provide information. You can also create bindings in
XAML that deliver data to the binding service and get back a result. As a
very simple demonstration, let’s look at a binding service that performs
the momentous feat of adding two numbers together. I call it Adder.
Example 1. Silverlight
Project: Petzold.Phone.Silverlight File: Adder.cs
using System.ComponentModel;
namespace Petzold.Phone.Silverlight { public class Adder : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged;
double augend = 0; double addend = 0; double sum = 0;
public double Augend { set { if (augend != value) { augend = value; OnPropertyChanged(new PropertyChangedEventArgs("Augend")); CalculateNewSum(); } } get { return augend; } }
public double Addend { set { if (addend != value) { addend = value; OnPropertyChanged(new PropertyChangedEventArgs("Addend")); CalculateNewSum(); } } get { return addend; } }
public double Sum { protected set { if (sum != value) { sum = value; OnPropertyChanged(new PropertyChangedEventArgs("Sum")); } }
get { return sum; } }
void CalculateNewSum() { Sum = Augend + Addend; }
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) { if (PropertyChanged != null) PropertyChanged(this, args); } } }
|
When you add two numbers
together, they can be called the Augend
and the Addend,
and that’s what the two properties are named. Both properties are of
type double and
both are entirely public, and when either is set to a new value, it
fires a PropertyChanged event and also
calls a method named CalculateNewSum.
CalculateNewSum adds
the Augend and Addend properties and sets the result to the Sum property. Sum
is a little different because the set
accessor is protected,
so nobody external to this class can mess with the Sum, and that is how it should be.
The SliderSum project shows one way to use this binding
service in a program. The Resources collection references two files from the
Petzold.Phone.Silverlight library:
Example 2. Silverlight
Project: SliderSum File: MainPage.xaml (excerpt)
<phone:PhoneApplicationPage.Resources> <petzold:Adder x:Key="adder" /> <petzold:StringFormatConverter x:Key="stringFormat" /> </phone:PhoneApplicationPage.Resources>
|
In the content area, two Slider elements are positioned at the top and bottom, and a
TextBlock occupies the larger
interior:
Example 3. Silverlight
Project: SliderSum File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" DataContext="{Binding Source={StaticResource adder}}"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions>
<Slider Grid.Row="0" Minimum="-100" Maximum="100" Margin="24" Value="{Binding Augend, Mode=TwoWay}" />
<Slider Grid.Row="2" Minimum="-100" Maximum="100" Margin="24" Value="{Binding Addend, Mode=TwoWay}" />
<TextBlock Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" Text="{Binding Sum, Converter={StaticResource stringFormat}, ConverterParameter=' {0:F2} '}" /> </Grid>
|
Notice the DataContext on the Grid. Although the two Slider controls are providing values for the Augend and Addend
properties, these Augend and Addend properties
cannot be binding targets because they are not backed by dependency
properties. The Adder
must be the binding source and the Slider controls must be the binding targets, and
that’s why the two bindings have a Mode of TwoWay.
The Slider
bindings are set initially to their center positions from the default
values defined by Adder, but
thereafter, the Slider
values are transferred to the Augend
and Addend properties. The TextBlock is bound to the Sum property with some string formatting.
Suppose you want to
display negative values
in red. (You are probably an accountant.) By this time you probably
know that a binding converter is involved. The converter can be generalized
somewhat by testing whether the value going into the converter is
greater than, equal to, or less than a certain criterion value. Each of
the three possibilities can result in a different brush being returned
from the converter. As in the converter in the BinaryClock project, this
information can be provided through public properties on the converter class, like
this:
Example 4. Silverlight
Project: Petzold.Phone.Silverlight File: ValueToBrushConverter.cs
using System; using System.Globalization; using System.Windows.Data; using System.Windows.Media;
namespace Petzold.Phone.Silverlight { public class ValueToBrushConverter : IValueConverter { public double Criterion { set; get; } public Brush GreaterThanBrush { get; set; } public Brush EqualToBrush { get; set; } public Brush LessThanBrush { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { double doubleVal = (value as IConvertible).ToDouble(culture); return doubleVal >= Criterion ? doubleVal == Criterion ? EqualToBrush : GreaterThanBrush : LessThanBrush; }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return null; } } }
|
Originally I wrote this
converter to just cast the value
argument to a double,
but I later found a need to use the converter with other numeric data types, so I went
for a more versatile conversion with an IConvertible
method.
The SliderSumWithColor project adds this converter to the
ever-growing Resources collection:
Example 5. Silverlight
Project: SliderSumWithColor File: MainPage.xaml (excerpt)
<phone:PhoneApplicationPage.Resources> <petzold:Adder x:Key="adder" /> <petzold:StringFormatConverter x:Key="stringFormat" /> <petzold:ValueToBrushConverter x:Key="valueToBrush" Criterion="0" LessThanBrush="Red" EqualToBrush="{StaticResource PhoneForegroundBrush}" GreaterThanBrush="{StaticResource PhoneForegroundBrush}" /> </phone:PhoneApplicationPage.Resources>
|
The property settings on the ValueToBrushConverter indicate that values less than zero
will be displayed in red; otherwise values are displayed in the PhoneForegroundBrush color.
Everything else is the
same as in the previous program except that the TextBlock now has a Binding
set on its Foreground property with
the ValueToBrushConverter:
Example 6. Silverlight
Project: SliderSumWithColor File: MainPage.xaml (excerpt)
<Grid . . . > . . . <TextBlock Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="48" Text="{Binding Sum, Converter={StaticResource stringFormat}, ConverterParameter=' {0:F2} '}"
Foreground="{Binding Sum, Converter={StaticResource valueToBrush}}" /> </Grid>
|
It’s actually quite exciting
to see the color of the TextBlock become red knowing that there’s no explicit event
handler in the program making this change: