I have the following setup. the problem is, that if I switch to the VisualState
"Alarm", the AlarmBrush
is not set. I have tried different "Bindings" (see below), but I only get errors like System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=AlarmBrush; DataItem=null; target element is 'DiscreteObjectKeyFrame' (HashCode=39320280); target property is 'Value' (type 'Object')
.
If I replace the value with an ResourceKey, then everything is fine. But I want to have this State dynamic, so a static resource is no opionion.
[TemplateVisualState(GroupName = "FooGroup", Name = "Alarm")]
public abstract class BaseClass : Control
{
public static readonly DependencyProperty AlarmBrushProperty = DependencyProperty.Register("AlarmBrush", typeof(Brush), typeof(BaseClass), null);
public Brush AlarmBrush
{
get { return (Brush)GetValue(AlarmBrushProperty); }
set { SetValue(AlarmBrushProperty, value); }
}
}
public class DerivedClass : BaseClass
{
public DerivedClass()
{
this.DefaultStyleKey = typeof(DerivedClass);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
VisualStateManager.GoToState(this, "Alarm", true);
}
}
<Style TargetType="Basic:DerivedClass">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Basic:DerivedClass">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="FooGroup">
<VisualState x:Name="Alarm">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background)" Storyboard.TargetName="AlarmBorder">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding AlarmBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type Basic:DerivedClass}}, Path=AlarmBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="AlarmBorder" BorderBrush="{TemplateBinding BorderBrush}" Padding="{TemplateBinding Padding}" BorderThickness="{TemplateBinding BorderThickness}">
<TextBlock Text="test" Foreground="{TemplateBinding Foreground}" TextWrapping="Wrap" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="BorderThickness" Value="5"/>
</Style>
<Foo:DerivedClass BorderBrush="#FFDA1F1F" AlarmBrush="#FF00FF0C"/>
You are going to hate this but I remember this is one of the limitations in WPF. The Value
property needs to be frozen which means you cannot use bindings to dynamically change it. Same thing goes to the To
property of a ColorAnimation
.
Since you are not actually animating the color (animating a Brush
will simply change the color instantly), you can always obtain a reference of the AlarmBorder
and manually set its Background
.