1
votes

I'd like to use the value of the Foreground of my control to be used as source for a VisualState ColorAnimation in a ControlTemplate.

My template definition looks mainly like the standard template for a ToggleButton, with some mods (marked as <<<.....>>>):

<Style TargetType="ToggleButton>
  <Setter .../>
  ...
  <<< <Setter Property="Foreground" Value="#FF000000"/> >>>
  ...
  <Setter .../>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="ToggleButton">
        <Grid>
          <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="CommonStates">
              <VisualState .../>
              <VisualState x:Name="PointerOver">
                <Storyboard>
                  <ColorAnimation Duration="0" Storyboard.Target="BackgroundGradient" Storybord.TargetProperty="(Rectangel.Fill).(GradientBrush.GradientStop)[1].(GradientStopColor)" <<< To="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}" >>> />
                </Storyboard>
              </VisualState>
      ...
    ...
  ...
</Style>
...
...
<ToggleButton <<< Foreground="#FFFF0000" >>> ...../>

So I expected to see the animation use the set foreground color (#FFFF0000) as part of the mouse over animation, but it did nothing at all. When I write To="#FFFF0000" in the animation definition, I get the expected result, but I'd like to keep the animation color dynamic and different for each ToggleButton in my app.

Any idea how to fix this?

Please!

Edit: After trying to achieve a similar effect as above by adding a new Rectangle with a LinearGradientBrush to the ContentPresenter where one GradientStop should be bound to {TemplateBinding Foreground}, I now get an error that might enlighten the reason for my problem "Object of type 'Windows.UI.xaml.DependencyProperty' cannot be converted to type 'System.Windows.DependencyProperty'." As it seems {TemplateBinding ...} produces a wrongly typed DependencyProperty or GradientStop expects a wrong type in Windows Store Apps. However! Is there a way to overcome this by explicit type cast in XAML or any other workaround?

Thanks

1

1 Answers

2
votes

So, I finally worked it out myself.

After getting an error message (see "Edit" of original post) I tried crafting a suitable converter and now I could kick myself, for not having seen the obvious!

It had nothing to do with WinRT or TemplateBinding or incompatibilities between Windows.UI.Xaml <-> and System-Windows objects.

I just did not realize that Foreground is a Brush type (in my case a SolidColorBrush) while GradientStopColor expects a Color!

Once I created a BrushToColorConverter and used this in connection with RelativeSource binding (since TemplateBinding does not allow converters) it worked.

  XAML:
<Page.Resources>
  <local:BrushToColorConverter x:Key="Brush2Color" DefaultOpacity="1.0"/>
</Page.Resources>
...
<ColorAnimation Duration="0" 
                Storyboard.TargetName="BackgroundGradient"
                Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" 
                To="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
                     Path=Foreground, 
                     Converter={StaticResource Brush2Color}, 
                     ConverterParameter=0.5}"
/>


CodeBehind:
public class BrushToColorConverter : IValueConverter
{
  private double defaultOpacity = 1;
  public double DefaultOpacity
  {
    set { defaultOpacity = value; }
  }

  public object Convert(object value, Type targetType, object parameter, string culture)
  {
    SolidColorBrush brush = value as SolidColorBrush;
    double opacity;

    if (!Double.TryParse((string)parameter, out opacity))
      opacity = defaultOpacity;

    if (brush == null)
      return Colors.Transparent;
    else
      return Color.FromArgb((byte)(255.0 * brush.Opacity * opacity), 
                            brush.Color.R, 
                            brush.Color.G, 
                            brush.Color.B
                           );
  }

  public object ConvertBack(object value, Type targetType, object parameter, string culture)
  {
    return null;
  }
}