视觉状态管理器用于管理带有状态的控件的状态以及用于状态过渡的逻辑。如button控件等。利用这个管理器可以使控件产生很多特殊效果。如:还没有上市的WP7的Panorama控件。
视觉状态是silverlight里比较重要的一块,它涉及到控件在各个状态下的视觉效果。视觉状态主要包括:Visual States(视觉状态),Visual State Groups(视觉状态组)和Visual Transitions(视觉过渡转换)。
Visual States: 是指控件在不同状态下显示的效果。如Button控件就含(Normal、MouseOver、Pressed、Disabled、Unfocused、Focused)六种状态。
Visual State Groups: 是为有互斥效果的控件提供的。对于相同的视觉状态组,是互斥的;对于不同的视觉状态组是不互斥的。
Visual Transitions:是视觉状态切换时的过渡动画效果。
<VisualStateManager.VisualStateGroups> //管理器类型.状态组
<VisualStateGroup> // 设置单个的状态组
<VisualStateGroup.Transitions> //视觉过渡转换,设置单个的状态组里不同状态切换时的动画效果
<VisualTransition From="Today" GeneratedDuration="0:0:0.5" To="Info">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-480"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-480"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualState x:Name="Info">//设置单个的状态的动画效果
<Storyboard>
<DoubleAnimation Duration="0" To="-480" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
对于生成状态的XAML代码,如果要产生复杂效果会写很长的代码,并不容易写和读,所以对于视觉状态的生成最好是用Expression Blend.目前的开发包中自带了这个工具,并且与vs2010是无缝切换的。
以按钮为例,以下XAML可以在按下按钮后,产生渐变动画,和位置移动。
<ControlTemplate x:Key="ButtonControlTemplate1" TargetType="Button">
<Grid x:Name="grid" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFF5820C" Offset="0"/>
<GradientStop Color="#FFF5820C" Offset="1"/>
<GradientStop Color="White" Offset="0.5"/>
</LinearGradientBrush>
</Grid.Background>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled"/>
<VisualState x:Name="Normal">
<Storyboard>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(LinearGradientBrush.StartPoint)" Storyboard.TargetName="grid">
<EasingPointKeyFrame KeyTime="0" Value="0.67,0.475"/>
<EasingPointKeyFrame KeyTime="0:0:1" Value="0.499,0.999"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(LinearGradientBrush.EndPoint)" Storyboard.TargetName="grid">
<EasingPointKeyFrame KeyTime="0" Value="0.33,0.525"/>
<EasingPointKeyFrame KeyTime="0:0:1" Value="0.501,0.001"/>
</PointAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(LinearGradientBrush.StartPoint)" Storyboard.TargetName="grid">
<EasingPointKeyFrame KeyTime="0" Value="0.134,0.653"/>
<EasingPointKeyFrame KeyTime="0:0:2" Value="1.122,-0.315"/>
</PointAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(LinearGradientBrush.EndPoint)" Storyboard.TargetName="grid">
<EasingPointKeyFrame KeyTime="0" Value="-0.114,1.341"/>
<EasingPointKeyFrame KeyTime="0:0:2" Value="0.874,0.373"/>
</PointAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="4.5"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
Panorama控件的实现(XAML):尽管这个控件微软已经有了官方版,但是这对于了解原理以及对于自定义控件还是很有用的。
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup" CurrentStateChanged="VisualStateGroup_CurrentStateChanged">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.5">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
<VisualTransition From="Test1" GeneratedDuration="0:0:0.5" To="Test2">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-480"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-480"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="Test1" GeneratedDuration="0:0:0.5" To="Test0">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="480"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="480"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="Test2" GeneratedDuration="0:0:0.5" To="Test3">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-480"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-960"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="Test3" GeneratedDuration="0:0:0.5" To="Test2">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-960"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-480"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="Test3" GeneratedDuration="0:0:0.5" To="Test4">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-960"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-1440"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="Test4" GeneratedDuration="0:0:0.5" To="Test3">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-1440"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-960"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="Test0" GeneratedDuration="0:0:0.5" To="Test1">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="480"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="Test2" GeneratedDuration="0:0:0.5" To="Test1">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid">
<EasingDoubleKeyFrame KeyTime="0" Value="-480"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Test0">
<Storyboard>
<DoubleAnimation Duration="0" To="480" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Test1"/>
<VisualState x:Name="Test2">
<Storyboard>
<DoubleAnimation Duration="0" To="-480" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Test3">
<Storyboard>
<DoubleAnimation Duration="0" To="-960" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Test4">
<Storyboard>
<DoubleAnimation Duration="0" To="-1440" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ContentGrid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>