Okay consider a simple simple problem.
I am trying to write a "Clock". I want to make it simple and seamless enough that you simply DataBind this control to a DateTime variable, and it should display the time. No, not a digital clock, but one with arms and legs. Okay just arms - an Hour arm, and a Minute Arm.
This sounds simple enough, seems like all I have to do for the hour arm is, set a RotateTransform to time.Hour * 30 degrees, right? (30 = 360/12).
So this syntax should work, right?
<RotateTransform Angle="{Binding Path=Hour*30}">
Bad news - that won't work! You cannot DataBind to a calculated value.
Okay, you can't DataBind like the above, but you can acheive what you are trying to by implementing a "Conversion" using the IValueConverter interface.
What the IValueConverter interface lets you do is, it lets you convert back and forth between a DataBound value, and what the real value is. So, an "Hour" value of 2, should translate to 60 degrees, and vice versa. This is a perfect job for a IValueConverter class.
So, go ahead and implement two IValueConverters, one for Minute and one for Hour as shown below -
public class HourToAngle : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime time = System.Convert.ToDateTime(value) ;
double Angle = time.Hour * 30;
Angle += 12 * time.Minute / 60;
return Angle;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Not required.
return null;
}
#endregion
}
public class MinuteToAngle : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime time = System.Convert.ToDateTime(value);
double Angle = time.Minute * 6;
return Angle;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Not required;
return null;
}
#endregion
}
Add the above converters to the front end XAML as resources -
<Grid.Resources>
<custom:HourToAngle x:Key="hourToAngle"/>
<custom:MinuteToAngle x:Key="minuteToAngle"/>
</Grid.Resources>
("custom" is a namespace I referenced in my XAML)
and then go ahead and implement the Binding as shown below -
<Rectangle x:Name="HourHand" Canvas.Top="21" Canvas.Left="48" Fill="Black" Width="4" Height="30">
<Rectangle.RenderTransform>
<RotateTransform x:Name="HourHand2" CenterX="2" CenterY="30" Angle="{Binding Mode=OneWay, Converter={StaticResource hourToAngle}}">
</RotateTransform>
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="MinuteHand" Canvas.Top="6" Canvas.Left="49" Fill="Black" Width="2" Height="45">
<Rectangle.RenderTransform>
<RotateTransform CenterX="1" CenterY="45" Angle="{Binding Mode=OneWay, Converter={StaticResource minuteToAngle}}">
</RotateTransform>
</Rectangle.RenderTransform>
</Rectangle>
The above is an extract out of a Clock Template I adopted from an article I saw on MSDN. For the full source of the Clock Template, please see here.
Now assuming that the ClockTemplate is defined somewhere in your XAML, you can use the template like this -
<Grid.Resources>
<ObjectDataProvider x:Key="dateTime" ObjectType="{x:Type s:DateTime}"/>
</Grid.Resources>
<Control Template="{StaticResource clockTemplate}"
Width="120" Height="108"
DataContext="{Binding Path=Now, Source={StaticResource dateTime}}">
</Control>
</Grid>
This will now produce a nice looking clock like this -
Mission Accomplished!!