Search code examples
silverlightcoding-stylevisualstatemanager

Silverlight Bind VisualState to different Targets


I'm using the following border style:

<!-- Border Style -->
<Style TargetType="Border">
    <Setter Property="Background">
        <Setter.Value>
            <LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5 ,0" MappingMode="RelativeToBoundingBox">
                <GradientStop Color="#00000000" Offset="0" />
                <GradientStop Color="#FFFFFEBB" Offset="0.116"/>
                <GradientStop Color="#FFFFFEBB" Offset="0.897"/>
                <GradientStop Color="#00000000" Offset="1" />
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="Opacity" Value="0"/>
    <Setter Property="OpacityMask">
        <Setter.Value>
            <LinearGradientBrush EndPoint="1.0 ,0.5" StartPoint="0.0 ,0.5" MappingMode="RelativeToBoundingBox">
                <GradientStop/>
                <GradientStop Color="#FF000000" Offset="0.1"/>
                <GradientStop Color="#FF000000" Offset="0.9"/>
                <GradientStop Color="#00000000" Offset="1"/>
            </LinearGradientBrush>
        </Setter.Value>
    </Setter>
    <Setter Property="RenderTransform">
        <Setter.Value>
            <CompositeTransform ScaleX="1.03" ScaleY="1.01"/>
        </Setter.Value>
    </Setter>
</Style>

There are three Borders in my application. I want to animate the opacity of the border when the mouse cursor is entering the border. In order to do that, I'm using a VisualState:

<VisualState x:Name="MouseOverState">
    <Storyboard>
        <DoubleAnimation To="1" Storyboard.TargetProperty="(UIElement.Opacity)" d:IsOptimized="True"/>
    </Storyboard>
</VisualState>

Do I need to define three different VisualStates and set the Storyboard.TargetName property? Or is there a way to use the same VisualState for many objects?

PS: I know that there is a TargetName and TargetObject Property in the GoToStateAction, but I can't get it to work:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="MouseEnter">
        <ei:GoToStateAction StateName="MouseOverState" TargetName="border0"/>
    </i:EventTrigger>
    <i:EventTrigger EventName="MouseLeave">
        <ei:GoToStateAction StateName="DefaultState" TargetName="border0"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

Solution

  • I'd be inclined to create a custom control deriving from the ContentControl.

    In themes\generic.xaml

    <Style TargetType="local:MyBorder">
        <Setter Property="Background">
            <Setter.Value>
                <LinearGradientBrush EndPoint="0.5, 1" StartPoint="0.5 ,0" MappingMode="RelativeToBoundingBox">
                    <GradientStop Color="#00000000" Offset="0" />
                    <GradientStop Color="#FFFFFEBB" Offset="0.116"/>
                    <GradientStop Color="#FFFFFEBB" Offset="0.897"/>
                    <GradientStop Color="#00000000" Offset="1" />
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="OpacityMask">
            <Setter.Value>
                <LinearGradientBrush EndPoint="1.0 ,0.5" StartPoint="0.0 ,0.5" MappingMode="RelativeToBoundingBox">
                    <GradientStop/>
                    <GradientStop Color="#FF000000" Offset="0.1"/>
                    <GradientStop Color="#FF000000" Offset="0.9"/>
                    <GradientStop Color="#00000000" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="RenderTransform">
            <Setter.Value>
                <CompositeTransform ScaleX="1.03" ScaleY="1.01"/>
            </Setter.Value>
        </Setter>
      <Setter Property="Foreground" Value="#FF000000"/>
      <Setter Property="Template">
          <Setter.Value>
              <ControlTemplate TargetType="local:MyBorder">
                <Border Background="{TemplateBinding Background}"
                           BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                     Opacity="0"
                 >
                    <vsm:VisualStateManager.VisualStateGroups>
                          <vsm:VisualStateGroup x:Name="CommonStates">
                              <vsm:VisualState x:Name="Normal"/>
                              <vsm:VisualState x:Name="MouseOver">
                                  <Storyboard>
                                      <DoubleAnimation To="1" Storyboard.TargetProperty="(UIElement.Opacity)" />
                                  </Storyboard>
                              </vsm:VisualState>
                          </vsm:VisualStateGroup >
                    </vsm:VisualStateManager>
                  <ContentPresenter
                      Content="{TemplateBinding Content}"
                      ContentTemplate="{TemplateBinding ContentTemplate}"
                      Cursor="{TemplateBinding Cursor}"
                      Margin="{TemplateBinding Padding}"
                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
              </ControlTemplate>
          </Setter.Value>
      </Setter>
    </Style>
    

    You just need to add the MouseEnter MouseLeave set the visual state of the control accordingly.

    Now you can simply drop local:MyBorder where you need one of these borders.