VisualStateManager.GoToState(Control, String, Boolean) 方法
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
藉由依名稱要求新的 VisualState ,轉換兩種狀態之間的控制項。
public:
static bool GoToState(Control ^ control, Platform::String ^ stateName, bool useTransitions);
static bool GoToState(Control const& control, winrt::hstring const& stateName, bool const& useTransitions);
public static bool GoToState(Control control, string stateName, bool useTransitions);
function goToState(control, stateName, useTransitions)
Public Shared Function GoToState (control As Control, stateName As String, useTransitions As Boolean) As Boolean
參數
- control
- Control
控制項要在之間轉換的兩個狀態。
- stateName
-
String
Platform::String
winrt::hstring
要切換的目標狀態。
- useTransitions
-
Boolean
bool
true 表示使用 VisualTransition 在狀態之間轉換。 false 表示略過使用轉換,並直接移至要求的狀態。 預設值為 false。
傳回
bool
如果控制項成功轉換為新狀態,或已經使用該狀態,則為true;否則為false。
範例
此範例示範使用 GoToState 方法在狀態之間轉換的控制邏輯。
private void UpdateStates(bool useTransitions)
{
if (Value >= 0)
{
VisualStateManager.GoToState(this, "Positive", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Negative", useTransitions);
}
if (isFocused)
{
VisualStateManager.GoToState(this, "Focused", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Unfocused", useTransitions);
}
}
Private Sub UpdateStates(ByVal useTransitions As Boolean)
If Value >= 0 Then
VisualStateManager.GoToState(Me, "Positive", useTransitions)
Else
VisualStateManager.GoToState(Me, "Negative", useTransitions)
End If
If isFocused Then
VisualStateManager.GoToState(Me, "Focused", useTransitions)
Else
VisualStateManager.GoToState(Me, "Unfocused", useTransitions)
End If
End Sub
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:NumericUpDownCustomControl"
>
<Style TargetType="local:NumericUpDown">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:NumericUpDown">
<Grid Margin="3"
Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ValueStates">
<!--Make the Value property red when it is negative.-->
<VisualState x:Name="Negative">
<Storyboard>
<ColorAnimation To="Red"
Storyboard.TargetName="TextBlock"
Storyboard.TargetProperty="(Foreground).(SolidColorBrush.Color)"/>
</Storyboard>
</VisualState>
<!--Return the control to its initial state by
return the TextBlock Foreground to its
original color.-->
<VisualState x:Name="Positive" />
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<!--Add a focus rectangle to highlight the entire control
when it has focus.-->
<VisualState x:Name="Focused">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisual"
Storyboard.TargetProperty="Visibility" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<!--Return the control to its initial state by
hiding the focus rectangle.-->
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border BorderThickness="1" BorderBrush="Gray"
Margin="7,2,2,2" Grid.RowSpan="2"
Background="#E0FFFFFF"
VerticalAlignment="Center"
HorizontalAlignment="Stretch">
<TextBlock x:Name="TextBlock" TextAlignment="Center" Padding="5"
Foreground="{TemplateBinding Foreground}"/>
</Border>
<RepeatButton Content="Up" Margin="2,5,5,0"
x:Name="UpButton"
Grid.Column="1" Grid.Row="0"
Foreground="Green"/>
<RepeatButton Content="Down" Margin="2,0,5,5"
x:Name="DownButton"
Grid.Column="1" Grid.Row="1"
Foreground="Green"/>
<Rectangle Name="FocusVisual" Grid.ColumnSpan="2" Grid.RowSpan="2"
Stroke="Red" StrokeThickness="1"
Visibility="Collapsed"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
備註
控制項邏輯會使用這個方法。 您通常只需要撰寫自訂控制項,或是使用應用層級邏輯來檢視狀態, (例如重新整理應用程式內容以取得應用程式視窗大小變更或方向) 。
當您呼叫這個方法時,預期會有一個 VisualState ,其 x:Name 值符合 您的 stateName 值、控制項範本中由 控制項識別的控制項,或做為應用程式的資源。 如果沒有,您不會收到例外狀況,但傳回值會是 false。 由 stateName命名的狀態可以位於指定之 Control範本中的任何VisualStateGroup元素中。 您可以追蹤哪些狀態是 VisualStateGroup ,以及知道當您從該群組指定新狀態時卸載哪些狀態。
使用 GoToState 時,通常未特別針對該控制項實例定義包含名稱所參考之視覺狀態的 ControlTemplate 。 相反地,視覺狀態來自預設控制項樣式,會載入為該控制項所有實例的隱含樣式。 如需隱含樣式概念的詳細資訊,請參閱 快速入門:控制項範本。
VisualStateManager 支援控制項作者的兩個重要功能,以及將自訂範本套用至控制項的應用程式開發人員:
- 控制項作者或應用程式開發人員使用VisualStateManager.VisualStateGroups附加屬性,將VisualStateGroup物件元素新增至 XAML 中控制項範本定義的根項目。 在 VisualStateGroup 元素內,每個 VisualState 都代表控制項的離散視覺狀態。 每個 VisualState 都有一個名稱,代表使用者可變更的 UI 狀態,或由控制項邏輯變更。 VisualState主要包含分鏡腳本。 此 Storyboard 會以個別相依性屬性值為目標,每當控制項處於該視覺狀態時,就應該套用這些值。
- 呼叫 VisualStateManager 的靜態 GoToState方法,控制這些狀態之間的作者或應用程式開發人員轉換。 每當控制項邏輯處理指出狀態變更的事件,或控制項邏輯自行起始狀態變更時,控制項作者就會執行此動作。 控制項定義程式碼通常會執行此動作,而不是應用程式程式碼,因此應用程式程式碼預設會有所有可能的視覺狀態及其轉換和觸發條件。 或者,它是變更視覺狀態的應用程式程式碼,用來管理應用層級檢視狀態,以回應使用者驅動變更主應用程式視窗的大小或方向。
當您呼叫 GoToState 來變更控制項的視覺狀態時, VisualStateManager 會執行下列動作:
- 首先,它會判斷是否符合 stateName 的狀態是否存在。 如果沒有,則不會發生任何事,而且方法會傳回 false。
- 如果依stateName命名的VisualState存在,而且有Storyboard,腳本就會開始。
- 如果控制項在新要求狀態之前,從該相同VisualStateGroup 使用的 VisualState 具有Storyboard,該分鏡腳本就會停止。 除了新 VisualState 套用動畫的特定屬性以外,控制項會還原為控制項範本及其組合中最初載入的狀態。
如果控制項已在要求為stateName的VisualState中,GoToState 會傳回true,但不會 (腳本不會重新開機) 。
常見的控制項實作模式是定義控制項類別的單一私用方法,負責處理控制項的所有可能 VisualState 變更。 要使用的視覺狀態是藉由檢查控制項的屬性來決定。 這些屬性可能是公用或私人屬性。 屬性的值會由 OnGotFocus等事件的控制項邏輯中的處理常式調整,並在設定視覺狀態之前立即檢查 Just-In-Time。 本主題中的程式碼範例會使用此實作模式。 或者,您可以從事件處理常式內呼叫個別狀態的 GoToState、從控制項事件處理常式覆寫 (OnEvent 方法) ,或從所有可能變更狀態的協助程式方法呼叫, (使用者驅動事件、自動化事件、初始化邏輯) 。
您也可以從自訂相依性屬性的 PropertyChangedCallback 實作中呼叫 GoToState。
視覺狀態和轉換
除了視覺狀態之外,視覺狀態模型也包含轉換。 轉換是由 腳本 所控制的動畫動作,這些動作會在狀態變更時于每個視覺狀態之間發生。 您可以針對控制項的一組視覺狀態所定義的開始狀態和結束狀態組合,以不同的方式定義轉換。 轉換是由VisualStateGroup的Transitions屬性所定義,通常定義于 XAML 中。 大部分的預設控制項範本不會定義轉換,在此情況下,狀態之間的轉換會立即發生。 如需詳細資訊,請參閱 VisualTransition。
您也可以定義 VisualTransition ,使其產生隱含轉換。 在VisualTransition的From或To視覺狀態中特別針對動畫設定任何相依性屬性,且狀態變更中具有不同值的任何相依性屬性,都可以使用隱含轉換動畫來產生動畫效果。 這個產生的動畫會使用插補,在 From 狀態值與這類屬性的 To 狀態值之間轉換。 隱含轉換動畫會持續到VisualTransition的 GeneratedDuration值所陳述的時間。 隱含轉換僅適用于 Double、 Color 或 Point 值的屬性。 換句話說,屬性必須使用DoubleAnimation、PointAnimation或ColorAnimation隱含產生動畫效果。 如需詳細資訊,請參閱 GeneratedDuration。
視覺狀態變更的事件
當控制項開始轉換 GoToState 呼叫所要求的狀態時,CurrentStateChanging就會引發。 如果 VisualTransition 套用至狀態變更,此事件會在轉換開始時發生。
CurrentStateChanged 會在控制項處於 GoToState 呼叫要求的狀態之後引發,就如同新的 Storyboard 開始一樣。 新分鏡腳本完成時不會引發任何事件。
如果未套用 VisualTransition , CurrentStateChanging 和 CurrentStateChanged 會連續快速引發,但如果兩者都發生,則會依該順序保證。
不過,如果狀態變更轉換遭到新的 GoToState 呼叫中斷,則不會針對第一個狀態轉換引發 CurrentStateChanged 事件。 針對下一個要求的狀態變更,會引發新的事件系列。
不會針對視覺狀態變更叫用OnApplyTemplate。 OnApplyTemplate 只會針對控制項的初始載入 XAML UI 叫用。
設定自訂控制項的具名視覺狀態
如果您要定義在其控制項範本 XAML 中有視覺狀態的自訂控制項,最佳做法是將控制項類別屬性設定為可控制取用的視覺狀態。 若要這樣做,請在控制項定義程式碼的類別層級套用一或多個 TemplateVisualState 屬性。 每個屬性都應該指定狀態的 x:Name 屬性,也就是控制項取用者傳入 GoToState 呼叫以使用該視覺狀態的 stateName 值。 如果 VisualState 是 VisualStateGroup的一部分,也應該在屬性定義中指出。
相關概念是控制項作者應該使用 TemplatePartAttribute來屬性主要控制群組件的名稱。 如果控制項取用者想要在套用範本之後從範本範圍存取具名元件,這會很有説明。 TemplateVisualStateAttribute 和 TemplatePartAttribute 合併說明定義控制項的控制項合約。
自訂 VisualStateManager
在進階案例中,您可以從 VisualStateManager 衍生,並變更預設的 GoToState 行為。 衍生類別應該覆寫受保護的 GoToStateCore 方法。 呼叫自訂 VisualStateManager 的任何實例時,都會使用此 Core 邏輯。
應用程式檢視狀態的視覺狀態
自訂控制項不一定有視覺狀態。 您可以使用新控制項範本的視覺狀態,這些範本會套用至您要藉由設定Template屬性來取代預設範本的任何控制項實例。 若要進行這項設定,您必須定義您打算使用的控制項範本和視覺狀態,做為 或 Application.Resources
中的 Page.Resources
樣式資源。 最好從預設範本的複本開始,並只修改範本的某些層面,甚至只修改某些視覺狀態,並單獨保留基本組合。 如需詳細資訊,請參閱快速入門:控制項範本。
視覺狀態可用來變更 頁面內頁面 的屬性或控制項,以考慮應用程式視窗方向。 您的組合或控制項的版面配置相關屬性值可能會根據整體方向為直向或橫向而變更。 如需 GoToState 此案例的詳細資訊,請參閱 快速入門:針對不同的視窗大小設計應用程式。
不是控制項之專案的視覺狀態
有時候,視覺狀態對於您想要變更某些 UI 區域的狀態不是立即 成為 Control 子類別的案例很有用。 您無法直接執行這項操作,因為 GoToState 方法的 控制項 參數需要 Control 子類別,這是指 VisualStateManager 作用的物件。 Page 是 Control 子類別,而且您很少會在沒有 Page的內容中顯示 UI,或者 Window.Content 根目錄不是 Control 子類別。 我們建議您將自訂 UserControl 定義為 Window.Content 根目錄,或是您想要將狀態套用至 (的容器,例如 Panel) 。 然後,您可以在 UserControl 上呼叫 GoToState,並套用狀態,而不論其餘的內容是否為 Control。 例如,您可以將視覺狀態套用至只包含 SwapChainPanel 的 UI,只要您將它放在 UserControl 中,並宣告要套用至父 UserControl 或範本中具名 SwapChainPanel 部分的屬性的具名狀態即可。