隨著VisualStateManager和State的出現,讓我們在實作使用者介面的狀態轉換上省了很大的工夫,不過VisualStateManager.GoToState這個Method在Silverlight和WPF的UserControl中都可以運作得很正常(因為Silverlight的MainWindow也繼承了UserControl)。
但是,如果在WPF的Window控制項裡面要利用這個方法來切換State的話,那可是你呼叫它一百次它都不會理你的,你不會看到畫面有任何反應,也不會有任何Exception被丟出來,不過,如果透過GoToStateAction的話倒是可以運作得很開心。
難道說在Window控制項中就不能透過程式進行State間的轉換了嗎!?
隨著VisualStateManager和State的出現,讓我們在實作使用者介面的狀態轉換上省了很大的工夫,不過VisualStateManager.GoToState這個Method在Silverlight和WPF的UserControl中都可以運作得很正常(因為Silverlight的MainWindow也繼承了UserControl)。
但是,如果在WPF的Window控制項裡面要利用這個方法來切換State的話,那可是你呼叫它一百次它都不會理你的,你不會看到畫面有任何反應,也不會有任何Exception被丟出來,不過,如果透過GoToStateAction的話倒是可以運作得很開心。
難道說在Window控制項中就不能透過程式進行State間的轉換了嗎!?
讓我們來做個簡單的小實驗,建立一個WPF專案,並且建立一個UserControl:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:ee="http://schemas.microsoft.com/expression/2010/effects"
mc:Ignorable="d"
x:Class="Wpf_GoToStateSample.TwoStateControl"
x:Name="UserControl"
d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup" ei:ExtendedVisualStateManager.UseFluidLayout="True">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1">
<ei:ExtendedVisualStateManager.TransitionEffect>
<ee:SlideInTransitionEffect/>
</ei:ExtendedVisualStateManager.TransitionEffect>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="State1">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="rectangle">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="State2">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ellipse">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="0.917*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<VisualStateManager.CustomVisualStateManager>
<ei:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<Rectangle x:Name="rectangle" Fill="Blue" Height="100" Stroke="Black" Width="100" Visibility="Collapsed"/>
<Ellipse x:Name="ellipse" Fill="Red" Stroke="Black" Width="100" Height="100" Visibility="Collapsed"/>
<Button Content="Change UserControl State" Grid.Row="1" d:LayoutOverrides="Height" Click="Button_Click" />
</Grid>
</UserControl>
using System.Windows;
using System.Windows.Controls;
namespace Wpf_GoToStateSample
{
public partial class TwoStateControl : UserControl
{
public TwoStateControl()
{
this.InitializeComponent();
}
private void Button_Click( object sender , RoutedEventArgs e )
{
if( this.rectangle.Visibility == Visibility.Visible )
{
//這邊用VisualStateManager.GoToState可以跑得很開心
VisualStateManager.GoToState( this , "State2" , true );
}
else
{
//這邊用VisualStateManager.GoToState可以跑得很開心
VisualStateManager.GoToState( this , "State1" , true );
}
}
}
}
接著把這個UserControl加到MainWindow中跑看看,如果沒意外的話,應該很開心的可以如下圖一樣的切換State。
![]() |
<-
-> |
![]() |
再來我們要在MainWindow中依樣畫葫蘆,在MainWindow中也加入兩個State,並且讓它切換:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:ee="http://schemas.microsoft.com/expression/2010/effects"
xmlns:local="clr-namespace:Wpf_GoToStateSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="Wpf_GoToStateSample.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup" ei:ExtendedVisualStateManager.UseFluidLayout="True">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1">
<ei:ExtendedVisualStateManager.TransitionEffect>
<ee:FadeTransitionEffect/>
</ei:ExtendedVisualStateManager.TransitionEffect>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="State1"/>
<VisualState x:Name="State2">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="twoStateControl">
<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<VisualStateManager.CustomVisualStateManager>
<ei:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<Button Content="Change Window State" Grid.Row="1" Click="Button_Click" />
<local:TwoStateControl x:Name="twoStateControl" d:LayoutOverrides="Height" Visibility="Collapsed" />
</Grid>
</Window>
using System.Windows;
namespace Wpf_GoToStateSample
{
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
}
private void Button_Click( object sender , RoutedEventArgs e )
{
if( this.twoStateControl.Visibility == Visibility.Visible )
{
//這個寫法完全起不了作用
VisualStateManager.GoToState( this , "State1" , true );
}
else
{
//這個寫法完全起不了作用
VisualStateManager.GoToState( this , "State2" , true );
}
}
}
}
很開心的執行看看的話,就會發現真的如同之前說的,完全起不了作用啊,一整個Orz....
不過!!!天無絕人之路!!還有兩招可以讓一切變得不一樣:
第一個方法是將原來的
VisualStateManager.GoToState( this , "State1" , true );
改成
VisualStateManager.GoToElementState( this.LayoutRoot , "State1" , true );
或是透過Microsoft.Expression.Interactivity.Core.ExtendedVisualStateManager的GoToElementState來達到一樣的目的~
Microsoft.Expression.Interactivity.Core.ExtendedVisualStateManager.GoToElementState( this.LayoutRoot , "State1" , true );
噹噹!!State又可以正常切換了!!
![]() |
<-
-> |
![]() |
最後一樣奉上原始碼,請自行服用!!