wpftriggerscustom-controlsreusabilityvisualstatemanager

How to change visualstate values and reuse the control with different properties values?


I've realized a custom textbox that changes BorderBrush on MouseOver event (in this case it changes the BorderBrush, but I can change other properties).

Now if I want to customize the color of BorderBrush on MouseOver and create different textboxes with different "BorderBrush on MouseOver" colors, how to do it using visualstates? Is there a way without define a different style for every textbox?

<ResourceDictionary>

    <Style TargetType="{x:Type local:IconTextBox}">
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="BorderBrush" Value="Black"/>

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:IconTextBox}">
                    <Border x:Name="Border"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    Background="{TemplateBinding Background}">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:0.5" />
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames
                                            Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
                                            Storyboard.TargetName="Border">
                                            <EasingColorKeyFrame KeyTime="0"
                                                Value="Green" />
                                                <!-- I want to change that Green -->

                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>

                        <ScrollViewer x:Name="PART_ContentHost"
                                    Focusable="False"
                                    HorizontalScrollBarVisibility="Hidden"
                                    VerticalScrollBarVisibility="Hidden" />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Solution

  • You don't need to have a separate style for changing the color. You can add a dependency property to your IconTextBox and change the color based on the property.

    Declare a dependency property in IconTextBox.cs:

    public Color MouseOverBorderBrushColor
    {
        get { return (Color)GetValue(MouseOverBorderBrushColorProperty); }
        set { SetValue(MouseOverBorderBrushColorProperty, value); }
    }
    
    public static readonly DependencyProperty MouseOverBorderBrushColorProperty =
        DependencyProperty.Register("MouseOverBorderBrushColor", typeof(Color), 
        typeof(IconTextBox), new PropertyMetadata(null));
    

    Bind to the property in your style:

    <ControlTemplate TargetType="{x:Type local:IconTextBox}">
        <Border x:Name="Border"
            BorderThickness="{TemplateBinding BorderThickness}"
            BorderBrush="{TemplateBinding BorderBrush}"
            Background="{TemplateBinding Background}">
            <Border.Resources>
                <ResourceDictionary>
                    <Storyboard x:Key="ColorStoryboard">
                        <ColorAnimationUsingKeyFrames
                        Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)"
                        Storyboard.TargetName="Border">
                            <EasingColorKeyFrame KeyTime="0"
                            Value="{Binding MouseOverBorderBrushColor, RelativeSource={RelativeSource TemplatedParent}}" />
                        </ColorAnimationUsingKeyFrames>
                    </Storyboard>
                </ResourceDictionary>
            </Border.Resources>
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualStateGroup.Transitions>
                        <VisualTransition GeneratedDuration="0:0:0.5" />
                    </VisualStateGroup.Transitions>
                    <VisualState x:Name="Normal" />
                    <VisualState x:Name="MouseOver" Storyboard="{StaticResource ColorStoryboard}" />
    
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
    
            <ScrollViewer x:Name="PART_ContentHost"
                Focusable="False"
                HorizontalScrollBarVisibility="Hidden"
                VerticalScrollBarVisibility="Hidden" />
        </Border>
    </ControlTemplate>
    

    Note that you can't use TemplatedParent in VisualStateManager hence I added the storyboard as a static resource to the resources of the border and used that in VisualStateManager. This trick is explained here.

    Then you can have IconTextBoxes with different mouse over border brush colors:

    <local:IconTextBox MouseOverBorderBrushColor="Green" />
    <local:IconTextBox MouseOverBorderBrushColor="Red" />