0

I am following along this awesome tutorial about custom controls, and in the fourth video of the playlist, Sean goes over visual states. In his AnalogClockStyle.xaml, he demonstrates a simple visual state manager inside the control's grid, but I can imagine this is not viable for more intricately designed custom controls if you just want to analyse their control templates.

Is there a way to separate out the visual state manager from the control template's style file? I would ideally like to create folders for Custom Control *.cs files, their control template *.xaml files, their respective style *.xaml files and finally their visual state manager files (if possible).

Here's what the current control template looks like:

<Style TargetType="local:AnalogClock">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:AnalogClock">
                <ControlTemplate.Resources>
                    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
                    <converters:GreaterThanMultiConverter x:Key="GreaterThanMultiConverter"/>
                    <converters:DivisionConverter x:Key="DivisionConverter"/>
                </ControlTemplate.Resources>
                <Grid x:Name="Clock" RenderTransformOrigin="0.5 0.5">
                    <Grid.RenderTransform>
                        <RotateTransform Angle="90"/>
                    </Grid.RenderTransform>

<!-- Move the Visual State Manager code to a separate file? -->
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="TimeStates">
                            <VisualState x:Name="Day">
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetName="ClockFill"
                                                Storyboard.TargetProperty="Color"
                                                To="SkyBlue"/>
                                    <ColorAnimation Storyboard.TargetName="HourStroke"
                                                Storyboard.TargetProperty="Color"
                                                To="Gold"/>
                                    <ColorAnimation Storyboard.TargetName="MinuteStroke"
                                                Storyboard.TargetProperty="Color"
                                                To="Gold"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Night">
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetName="ClockFill"
                                                Storyboard.TargetProperty="Color"
                                                To="Black"/>
                                    <ColorAnimation Storyboard.TargetName="HourStroke"
                                                Storyboard.TargetProperty="Color"
                                                To="White"/>
                                    <ColorAnimation Storyboard.TargetName="MinuteStroke"
                                                Storyboard.TargetProperty="Color"
                                                To="White"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Christmas">
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetName="ClockFill"
                                                Storyboard.TargetProperty="Color"
                                                To="Green"/>
                                    <ColorAnimation Storyboard.TargetName="HourStroke"
                                                Storyboard.TargetProperty="Color"
                                                To="Red"/>
                                    <ColorAnimation Storyboard.TargetName="MinuteStroke"
                                                Storyboard.TargetProperty="Color"
                                                To="Red"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
<!-- Move the Visual State Manager code to a separate file? -->

                    <Ellipse x:Name="PART_Clock" Stroke="Black" StrokeThickness="1">
                        <Ellipse.Style>
                            <Style TargetType="Ellipse">
                                <Setter Property="Width" Value="{Binding ActualHeight, ElementName=Clock}"/>
                                <Setter Property="Height" Value="auto"/>
                                <Style.Triggers>
                                    <DataTrigger Value="True">
                                        <DataTrigger.Binding>
                                            <MultiBinding Converter="{StaticResource GreaterThanMultiConverter}">
                                                <MultiBinding.Bindings>
                                                    <Binding Path="ActualHeight" ElementName="Clock"/>
                                                    <Binding Path="ActualWidth" ElementName="Clock"/>
                                                </MultiBinding.Bindings>
                                            </MultiBinding>
                                        </DataTrigger.Binding>
                                        <DataTrigger.Setters>
                                            <Setter Property="Height" Value="{Binding ActualWidth, ElementName=Clock}"/>
                                            <Setter Property="Width" Value="auto"/>
                                        </DataTrigger.Setters>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </Ellipse.Style>
                        <Ellipse.Fill>
                            <SolidColorBrush x:Name="ClockFill" Color="White"/>
                        </Ellipse.Fill>
                    </Ellipse>

                    <Line x:Name="PART_HourHand" StrokeThickness="1" VerticalAlignment="Center" HorizontalAlignment="Center" X1="0" 
                        X2="{Binding ActualHeight, ElementName=PART_Clock, Converter={StaticResource DivisionConverter}, ConverterParameter=-4}">
                        <Line.Stroke>
                            <SolidColorBrush x:Name="HourStroke" Color="Black"/>
                        </Line.Stroke>
                    </Line>
                    <Line x:Name="PART_MinuteHand" StrokeThickness="1" VerticalAlignment="Center" HorizontalAlignment="Center" X1="0" 
                        X2="{Binding ActualHeight, ElementName=PART_Clock, Converter={StaticResource DivisionConverter}, ConverterParameter=-2.5}">
                        <Line.Stroke>
                            <SolidColorBrush x:Name="MinuteStroke" Color="Black"/>
                        </Line.Stroke>
                    </Line>

                    <Line x:Name="PART_SecondHand" Visibility="{TemplateBinding ShowSeconds, Converter={StaticResource BooleanToVisibilityConverter}}" Stroke="Red" StrokeThickness="1" VerticalAlignment="Center" HorizontalAlignment="Center" X1="0"
                        X2="{Binding ActualHeight, ElementName=PART_Clock, Converter={StaticResource DivisionConverter}, ConverterParameter=-2.5}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
JansthcirlU
  • 688
  • 5
  • 21
  • You can inherit styles to combine setters of different properties, triggers, etc, but you [can't inherit control templates](https://stackoverflow.com/q/2034511/1997232) to have in one `VisualStateGroup`. It's not a visual to store it in resources with key and then use `ContentControl` to show. Maybe a xaml extension/attached behavior will do? Though I recall creating templates in code behind is a nightmare. – Sinatr Sep 22 '20 at 08:32
  • I see, that's unfortunate. – JansthcirlU Sep 22 '20 at 09:22
  • No you can't. `VisualStateManager.VisualStateGroups` is an attached read-only property (collection), which has to be set locally. If this property wouldn't be read-only, you could use a `Style.Setter` to set it from a `Style` resource. – BionicCode Sep 22 '20 at 20:36

0 Answers0