I am learning how to work with VisualStates, and have this problem:
I have a Control template which has Grid inside, and grid contains image and two TextBlocks. I would like to place a rectangle whenever a mouse if over a control. Most of the examples on internet use Blend, which I currently don’t have, and also I would like to learn to do this manually. Here is a simple template (I have used constant colors to make it simpler):
<ControlTemplate x:Key="MyControlTemplate" TargetType="SomeControl">
<Grid Cursor="Hand" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2" HorizontalAlignment="Left" VerticalAlignment="Top" Stretch="None" Source="{Binding ImageUrl}" />
<TextBlock x:Name="TitleElement" Grid.Column="1" Margin="4" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Content}" Foreground="{StaticRecource TitleForegroundBrush}" />
<TextBlock x:Name="DescriptionElement" Grid.Row="1" Grid.Column="1" Margin="4,0,4,4" MaxWidth="200" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Description}" Foreground="{StaticResource DescriptionElementForeground}" />
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TitleElement" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{StaticResource TitleElementFocusedForeground}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
Changing the TitleElement’s Foreground on mouse over is working. Now I would like to have a border over whole control on mouse over (not just part of it). First thing I tried is placing a Border as a container of grid and putting a StoryBoard inside VisualStateGroup:
<Border x:Name="ControlBorder" BorderBrush="{StaticResource ControlBorderBrush}" BorderThickness="0">
<Grid Cursor="Hand" Width="Auto">
....
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Unfocused"/>
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TitleElement" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{StaticResource TitleElementFocusedForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ControlBorder" Storyboard.TargetProperty="BorderThickness">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="1" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
This didn’t work, as a matter of fact, now TitleElement doesn’t even change foreground color, as it used to. However, adding a Border as 4th element inside a grid (RowSpan and ColumnSpan set to whole grid) works!, but there are some side affects which I don’t like, for example, rectangle is “blinking” when I am moving mouse over control. Questions:
- Why putting Grid inside Rectangle doesn’t work, but putting Rectangle inside grid works?
- I see that there is a CommonStates VisualGroup, which must be predefined somewhere. How do we know which ones are predefined, and their respective names?
- What is the scope of VisualStateManager? If I define it inside an element, does it belong just to that element, or whole ControlTemplate?
Thanks.
Visual states need to be managed on the root element of the control template, if you put an element around your root they will be ignored, you will need to move them up.
On the styles and templates page of the controls the specific states are listed, common states should be the same for all (as they are “common”), the ones which are supported are also listed on the pages for the controls. (e.g.
ButtonhasNormal,Pressed,MouseOverandDisabled)Applies to the whole template (see 1.)