Visual States in WPF 4.0

来源:互联网 发布:网站存在sql注入漏洞 编辑:程序博客网 时间:2024/06/17 04:12

Visual States in WPF 4.0

Visual States, from the coined term, signifies the current state of display. In WPF, we can refer visual states to controls or even windows. For example a button can have a pressed state or a hover state, the same thing can be applied on the entire window whether we can show that what is being displayed is the login state (with the controls and login button) or in the main user workspace state. Additionally in WPF, we can define “Visual Transitions”, same as Microsoft Powerpoint’s slides transitioning, whereby entering from one slide (or visual state) to another may have a fading or whatever transition effects.

Visual States was introduced in the Silverlight first, and then it was introduced into WPF Toolkit continue, Microsoft Expression Blend 2.5 and later supports Visual State Manager to develop the style/template. WPF 4 introduces Visual State Manager that user can set visual states in the control template and manage to transit the states based on the different conditions. Visual State Manager class seems the trigger in the template, but it can organize the properties of the states rationally and transit the different visual states easily through VisualTransition class.

Declaring Visual States in XAML

Our visual states are maintained by a VisualStateManager. We need to define a group of visual states first. We can place the following tags inside the hosting element that will be performing the visual state transitions:

?
1
2
3
4
5
6
7
8
9
10
11
12
<UserControlx:Class="Desktop.Shell.MainView"
  xmlns:vw="clr-namespace:Desktop.Shell.Views">
  <Grid>
    <VisualStateManager.VisualStateGroups>
      <VisualStateGroupx:Name="MainVisualStateGroup">
        <VisualStatex:Name="LoginState"/>
     </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <vw:LoginView/>
   <vw:WorkspaceViewOpacity="0"/>
  </Grid>
</UserControl>

A visual state group will contain related visual states where the visual transitions will be able to use in moving from one state to another. For more info see: VisualStateGroup.

From the above example, we are creating a default visual state which is a login state. This state is whatever is the current display: visibility, locations and styles of the controls. The current state of display is that our login view (our login user control) is visible while the workspace view is not as noted by Opacity=0.

In here I chose Opacity since we can control how faded our view can be as well as visibility. Due to opacity value, our transition can score from 0 incrementing by 0.1 until it reaches full visibility to 1.

Next we are going to create our second visual state and with fading transition of course:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<UserControlx:Class="Desktop.Shell.MainView"
  xmlns:vw="clr-namespace:Desktop.Shell.Views">
  <Gridx:Name="mainGrid">
    <VisualStateManager.VisualStateGroups>
      <VisualStateGroupx:Name="MainVisualStateGroup">
        <VisualStatex:Name="LoginState"/>
        <VisualStatex:Name="WorkspaceState">
          <StoryBoard>
            <DoubleAnimationUsingKeyFramesStoryboard.TargetProperty="Opacity"Storyboard.TargetName="loginView">
              <EasingDoubleKeyFrameKeyTime="0"Value="1"/>
              <EasingDoubleKeyFrameKeyTime="0:0:0.2"Value="0"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFramesStoryboard.TargetProperty="Opacity"Storyboard.TargetName="workspaceView">
              <EasingDoubleKeyFrameKeyTime="0"Value="0"/>
              <EasingDoubleKeyFrameKeyTime="0:0:0.2"Value="1"/>
            </DoubleAnimationUsingKeyFrames>
          </StoryBoard>
        </VisualState>
      </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <vw:LoginViewx:Name="loginView"/>
    <vw:WorkspaceViewx:Name="workspaceView"Opacity="0"/>
  <Grid>
 </UserControl>

From the above example, we added a new visual state named Workspace state. Inside we declared a storyboard animation with two double animation using key frames. We use double since the type of the value of the target property which is Opacity is double.

The first animation targets our login view and its opacity property. At key time 0, we declared the value as 1 which is the default opacity of this view. At key time 0.2 seconds, we declared value of 0. This means that this animation will transition the opacity value from 1 to 0 in 0.2 seconds making a fading out effect.

The second animation targets our workspace view and its opacity property. Since we are going to make this view visible, at key time 0, we declared the value as 0 which is the invisibility of this view. At key time 0.2 seconds, we declared value of 1. This means that this animation will transition the opacity value from 0 to 1 in 0.2 seconds making a fading in effect.

Changing from one state to another

Now that we have our declared states and animation. The only thing required is to let our visual state manager execute state transitions to move to another state. In code we only need to call GoToState method of VisualStateManager:

?
1
VisualStateManager.GoToState(mainGrid, "WorkspaceState"true);

Parameters are:

  1. The Control containing the visual state. For this case its the grid.
  2. The name of the state to transition.
  3. Flag whether to use transitions (our declared storyboard) or not.

Since this is currently called in C#, we can further enhance to coincide with MVVM pattern by creating a dependency attached property:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
publicclass StateManager : DependencyObject
{
    publicstatic string GetVisualStateProperty(DependencyObject obj)
    {
        return(string)obj.GetValue(VisualStatePropertyProperty);
    }
    publicstatic void SetVisualStateProperty(DependencyObject obj, stringvalue)
    {
        obj.SetValue(VisualStatePropertyProperty, value);
    }
    publicstatic readonly DependencyProperty VisualStatePropertyProperty =
        DependencyProperty.RegisterAttached(
        "VisualStateProperty",
        typeof(string),
        typeof(StateManager),
        newPropertyMetadata((dependencyObject, args) =>
        {
            var frameworkElement = dependencyObject asFrameworkElement;
            if(frameworkElement == null)
                return;
            VisualStateManager.GoToState(frameworkElement, (string)args.NewValue, true);
        }));
}

This way we can create a class where we can just set the State property:

?
1
MainViewModel.ViewState = "workspaceState"

and bind that property to the view using this attached property method:

?
1
StateManager.VisualStateProperty = "{Binding Path=ViewState}"

And that’s it. I enjoyed visual states and using Microsoft Expression Blend’s powerful animation wysiwyg editor, we can easily create custom animations.

Enjoy!

原创粉丝点击