視覺狀態
.NET 多平臺應用程式 UI (.NET MAUI) Visual State Manager 提供結構化的方式,從程式代碼對使用者介面進行視覺變更。 在大部分情況下,應用程式的使用者介面是在 XAML 中定義,而這個 XAML 可以包含標記,描述 Visual State Manager 如何影響使用者介面的視覺效果。
Visual State Manager 引進視覺狀態的概念。 例如的 .NET MAUI 檢視 Button 可能會根據其基礎狀態而有不同的視覺外觀,無論是停用或按下,還是具有輸入焦點。 這些是按鈕的狀態。 視覺狀態會收集於視覺狀態群組中。 視覺狀態群組中的所有視覺狀態都是互斥的。 視覺狀態和視覺狀態群組都是透過簡單的文字字串來識別。
.NET MAUI Visual State Manager 會以下列視覺狀態定義名為 CommonStates
的視覺狀態群組:
- 一般
- 停用
- 焦點
- Selected
- PointerOver
衍生Normal
自 VisualElement的所有類別都支援、Disabled
、 Focused
和 PointerOver
視覺狀態,這是 和Page的基類View。 此外,您也可以定義自己的視覺狀態群組和視覺狀態。
使用 Visual State Manager 來定義外觀,而不是直接從程式代碼後置存取視覺元素的優點,就是您可以控制視覺元素在 XAML 中完全回應不同狀態的方式,這會將所有 UI 設計保留在一個位置。
注意
觸發程式也可以根據檢視屬性的變更或引發事件,對使用者介面中的視覺效果進行變更。 不過,使用觸發程式來處理這些變更的各種組合可能會造成混淆。 使用 Visual State Manager 時,視覺狀態群組內的視覺狀態一律互斥。 在任何時候,每個群組中只有一個狀態是目前的狀態。
常見的視覺狀態
Visual State Manager 可讓您在 XAML 檔案中包含標記,如果檢視正常、停用、已選取輸入焦點、已選取滑鼠游標停留在檢視上方但未按下,則可以變更檢視的視覺外觀。 這些稱為 常見狀態。
例如,假設您在頁面上有檢視 Entry ,而且您想要以下列方式變更 的 Entry 視覺效果外觀:
- Entry停用 時Entry,應該會有粉紅色的背景。
- Entry通常應該有石灰背景。
- 當 Entry 其具有輸入焦點時,應該會展開至其正常高度的兩倍。
- Entry當滑鼠游標停留在它上方但未按下時,應該會有淺藍色背景。
您可以將 Visual State Manager 標記附加至個別檢視,或者如果套用至多個檢視,則可以在樣式中定義它。
在檢視上定義視覺狀態
類別 VisualStateManager
會 VisualStateGroups
定義附加屬性,用來將視覺狀態附加至檢視。 屬性 VisualStateGroups
的類型為 VisualStateGroupList
,這是物件的集合 VisualStateGroup
。 因此,附加屬性的 VisualStateManager.VisualStateGroups
子系是 VisualStateGroup
物件。 這個物件會 x:Name
定義屬性,指出群組的名稱。 或者,類別 VisualStateGroup
會 Name
定義您可以改用的屬性。 如需附加屬性的詳細資訊,請參閱 附加屬性。
類別 VisualStateGroup
會定義名為 States
的屬性,這是物件的集合 VisualState 。 States
是類別的內容屬性 VisualStateGroups
,因此您可以將 物件包含 VisualState 為 的 VisualStateGroup
子系。 每個 VisualState 物件都應該使用 x:Name
或 Name
來識別。
類別 VisualState 會定義名為 Setters
的屬性,這是物件的集合 Setter 。 這些是您在物件中使用的Style相同Setter物件。 Setters
不是的內容屬性 VisualState,因此必須包含 屬性的屬性項目標記 Setters
。 Setter 對象應該插入為 的 Setters
子系。 當該狀態為目前時,每個 Setter 物件都會指出屬性的值。 對象所參考 Setter 的任何屬性都必須由可繫結屬性支援。
重要
為了讓視覺狀態 Setter 物件正常運作, VisualStateGroup
必須包含 VisualState 狀態的 Normal
物件。 如果這個視覺狀態沒有任何 Setter 物件,它應該包含為空的視覺狀態 (<VisualState Name="Normal" />
)。
下列範例顯示 上 Entry定義的視覺狀態:
<Entry FontSize="18">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
<VisualState Name="PointerOver">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightBlue" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
</Entry>
下列螢幕快照顯示 Entry 其四個已定義的視覺狀態:
Entry當 處於 狀態時Normal
,其背景會是石灰。 當取得輸入焦點時 Entry ,其字型大小會加倍。 Entry當 變成停用時,其背景會變成粉紅色。 在 Entry 取得輸入焦點時,不會保留其石灰背景。 當滑鼠指標停留在 Entry上方,但未按下時, Entry 背景會變成淺藍色。 當 Visual State Manager 在視覺狀態之間切換時,先前狀態所設定的屬性會取消設定。 因此,視覺狀態互斥。
如果您想要 Entry 在狀態中 Focused
具有石灰背景,請將另一個 Setter 新增至該視覺狀態:
<VisualState Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
在樣式中定義視覺狀態
通常必須在兩個或多個檢視中共用相同的視覺狀態。 在此案例中,視覺狀態可以在 中 Style定義。 您可以藉由為 屬性新增 Setter 對象 VisualStateManager.VisualStateGroups
來達成此目的。 物件的 content 屬性是其 Value
屬性Setter,因此可以指定為 物件的子系Setter。 屬性 VisualStateGroups
的類型為 VisualStateGroupList
,因此物件的子系 Setter 是 VisualStateGroupList
VisualStateGroup
,可以加入包含 VisualState 物件的 。
下列範例顯示 的隱含樣式 Entry ,其定義通用視覺狀態:
<Style TargetType="Entry">
<Setter Property="FontSize" Value="18" />
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Focused">
<VisualState.Setters>
<Setter Property="FontSize" Value="36" />
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Disabled">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Pink" />
</VisualState.Setters>
</VisualState>
<VisualState Name="PointerOver">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightBlue" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
當這個樣式包含在頁面層級資源字典中時, Style 物件將會套用至頁面上的所有 Entry 物件。 因此,頁面上的所有 Entry 物件都會以相同的方式回應其視覺狀態。
.NET MAUI 中的視覺狀態
下表列出 .NET MAUI 中定義的視覺狀態:
類別 | 狀態 | 相關資訊 |
---|---|---|
Button | Pressed |
按鈕視覺狀態 |
CarouselView | DefaultItem 、 、 CurrentItem 、 PreviousItem NextItem |
CarouselView 視覺效果狀態 |
CheckBox | IsChecked |
CheckBox 視覺效果狀態 |
CollectionView | Selected |
CollectionView 視覺狀態 |
ImageButton | Pressed |
ImageButton 視覺狀態 |
RadioButton | Checked , Unchecked |
RadioButton 視覺狀態 |
Switch | On , Off |
切換視覺狀態 |
VisualElement | Normal 、 、 Disabled 、 Focused PointerOver |
常見狀態 |
在多個元素上設定狀態
在先前的範例中,視覺狀態已附加至單一元素並操作。 不過,您也可以建立附加至單一元素的視覺狀態,但在相同範圍內設定其他元素的屬性。 這可避免在狀態運作的每個元素上重複視覺狀態。
此 Setter 類型具有 TargetName
類型的 string
屬性,代表視覺狀態將操作的目標物件 Setter 。 TargetName
定義 屬性時,會將 Setter 中TargetName
定義的 物件的 設定Property
為 Value
:
<Setter TargetName="label"
Property="Label.TextColor"
Value="Red" />
在這裡範例中, Label 具名 label
的 屬性 TextColor
會設定為 Red
。 設定 屬性時, TargetName
您必須在 中 Property
指定 屬性的完整路徑。 因此,若要在 上LabelProperty
設定 TextColor
屬性,會指定為 Label.TextColor
。
注意
對象所參考 Setter 的任何屬性都必須由可繫結屬性支援。
下列範例示範如何從單一視覺狀態群組設定多個物件的狀態:
<StackLayout>
<Label Text="What is the capital of France?" />
<Entry x:Name="entry"
Placeholder="Enter answer" />
<Button Text="Reveal answer">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal" />
<VisualState Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
<Setter TargetName="entry"
Property="Entry.Text"
Value="Paris" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
</StackLayout>
在此範例中Normal
,當 未按下 時Button,狀態為使用中,而且可以輸入回應。Entry Pressed
按下 時Button狀態會變成使用中狀態,並指定其Scale
屬性將從預設值 1 變更為 0.8。 此外, Entry 該名 entry
將將其 Text
屬性設定為巴黎。 因此,結果是按下 Button 時會重新調整為稍微小一點,而 Entry 顯示巴黎:
然後,發行 時 Button ,它會重新調整為預設值 1,並 Entry 顯示任何先前輸入的文字。
重要
指定屬性的 元素TargetName
不支援Setter屬性路徑。
定義自定義視覺狀態
您可以藉由定義自定義視覺狀態來實作,因為您可以定義通用狀態的視覺狀態,但使用您選擇的名稱,然後呼叫 VisualStateManager.GoToState
方法來啟動狀態。
下列範例示範如何使用 Visual State Manager 進行輸入驗證:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VsmDemos.VsmValidationPage"
Title="VSM Validation">
<StackLayout x:Name="stackLayout"
Padding="10, 10">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="ValidityStates">
<VisualState Name="Valid">
<VisualState.Setters>
<Setter TargetName="helpLabel"
Property="Label.TextColor"
Value="Transparent" />
<Setter TargetName="entry"
Property="Entry.BackgroundColor"
Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="Invalid">
<VisualState.Setters>
<Setter TargetName="entry"
Property="Entry.BackgroundColor"
Value="Pink" />
<Setter TargetName="submitButton"
Property="Button.IsEnabled"
Value="False" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="Enter a U.S. phone number:"
FontSize="18" />
<Entry x:Name="entry"
Placeholder="555-555-5555"
FontSize="18"
Margin="30, 0, 0, 0"
TextChanged="OnTextChanged" />
<Label x:Name="helpLabel"
Text="Phone number must be of the form 555-555-5555, and not begin with a 0 or 1" />
<Button x:Name="submitButton"
Text="Submit"
FontSize="18"
Margin="0, 20"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
在此範例中,視覺狀態會附加至 StackLayout,而且有兩個名為 和Invalid
的互斥狀態Valid
。 Entry如果 不包含有效的電話號碼,則目前的狀態為 Invalid
,因此 Entry 具有粉紅色背景,則會顯示第二Label個,且 Button 已停用。 輸入有效的電話號碼時,目前的狀態會 Valid
變成 。 會 Entry 取得石灰背景,第二個 Label 消失,而 Button 現在已啟用:
程序代碼後置檔案負責處理 TextChanged
中的 Entry事件。 處理程式會使用正則表示式來判斷輸入字串是否有效。 程式GoToState
代碼後置檔案中的 方法會呼叫 物件上的StackLayout靜態VisualStateManager.GoToState
方法:
public partial class VsmValidationPage : ContentPage
{
public VsmValidationPage()
{
InitializeComponent();
GoToState(false);
}
void OnTextChanged(object sender, TextChangedEventArgs args)
{
bool isValid = Regex.IsMatch(args.NewTextValue, @"^[2-9]\d{2}-\d{3}-\d{4}$");
GoToState(isValid);
}
void GoToState(bool isValid)
{
string visualState = isValid ? "Valid" : "Invalid";
VisualStateManager.GoToState(stackLayout, visualState);
}
}
在此範例中,會 GoToState
從建構函式呼叫 方法,以初始化狀態。 一律應該有目前的狀態。 程式代碼後置檔案接著會在定義視覺狀態的 物件上,使用狀態名稱呼叫 VisualStateManager.GoToState
。
視覺狀態觸發程式
視覺狀態支持狀態觸發程式,這是一組特殊的觸發程式,可定義應套用 的條件 VisualState 。
狀態觸發程序會新增至 VisualState 的 StateTriggers 集合。 此集合可以包含單一狀態觸發程序或多個狀態觸發程序。 當集合中的任何狀態觸發程序為作用中時,將會套用 VisualState。
使用狀態觸發程式來控制視覺狀態時,.NET MAUI 會使用下列優先順序規則來判斷哪一個觸發程式 (以及對應的 VisualState) 為作用中:
- 衍生自 StateTriggerBase 的任何觸發程序。
- 因為符合 MinWindowWidth 條件,所以已啟用 AdaptiveTrigger。
- 因為符合 MinWindowHeight 條件,所以已啟用 AdaptiveTrigger。
如果多個觸發程序同時處於作用中狀態 (例如,兩個自訂觸發程序),則會優先使用標記中宣告的第一個觸發程序。
如需狀態觸發程式的詳細資訊,請參閱 狀態觸發程式。