Содержание
Элементы управления .NET MAUI могут находится в различных состояниях. например, кнопка может быть нажата или отключена, поле ввода может иметь фокус и так далее. При необходимости, мы можем менять оформление элемента управления в зависимости от его состояния. Для этого в .NET MAUI используется Visual State Manager (менеджер визуальных состояний)
Общие состояния элементов
Менеджер визуальных состояний определяет специальную группу с названием CommonStates для состояний в которых могут находиться элементы управления, производные от VisualElement. К этом состояниям относятся:
NormalDisabledFocusedSelectedPointerOver
Эти состояния являются взаимоисключающими. То есть в любое время только одно состояние может быть текущим (активным), например, кнопка не может быть одновременно в состояниях Normal и Disabled. Рассмотрим как мы можем менять внешний вид элемента управления в зависимости от его состояния.
Определение визуальных состояний в элементе управления
Рассмотрим как использовать менеджер визуальных состояний на примере обычной кнопки Button. Создайте новый проект .NET MAUI и измените код MainPage.xaml следующим образом:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Vsm.MainPage">
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Button
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
HorizontalOptions="Fill" >
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="PointerOver">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightBlue" />
<Setter Property="BorderWidth" Value="3"/>
<Setter Property="BorderColor" Value="DarkBlue"/>
</VisualState.Setters>
</VisualState>
<VisualState Name="Pressed">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightCoral" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
</Button>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Рассмотрим этот код подробно. Итак, чтобы определить визуальные состояния элемента мы используем присоединенное свойство VisualStateManager.VisualStateGroups.
<VisualStateManager.VisualStateGroups>
тут прочий код
</VisualStateManager.VisualStateGroups>
Это свойство представляет из себя коллекцию VisualStateGroupList, которая должна содержать объекты VisualStateGroup. В этой коллекции мы определяем новую группу визуальных состояний с именем CommonStates:
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup Name="CommonStates">
//тут прочий код
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
Внутри этой группы мы определяем три состояния для кнопки — Normal, PointerOver и Pressed, то есть для кнопки в обычном состоянии, когда над кнопкой находится курсор мыши и когда кнопка нажата. Каждое из состояний представляет из себя объект типа VisualState с именем равным имени состояния. Содержимое объекта — список объектов Setter (как и у стилей) в которых мы определяем значения для каких-либо визуальных свойств элемента управления. Так, например, когда над кнопкой находится курсор мыши, то мы устанавливаем значения трех свойств:
<VisualState Name="PointerOver">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightBlue" />
<Setter Property="BorderWidth" Value="3"/>
<Setter Property="BorderColor" Value="DarkBlue"/>
</VisualState.Setters>
</VisualState>
Проверим работу приложения. Так будет выглядеть наша кнопка при запуске приложения
при наведении курсора мыши
при нажатии на кнопку
Определение визуальных состояний в стиле
Визуальные состояния можно определять непосредственно в стилях элементов. Перепишем наш пример с использованием стиля для кнопки:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Vsm.MainPage">
<ContentPage.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Lime" />
</VisualState.Setters>
</VisualState>
<VisualState Name="PointerOver">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightBlue" />
<Setter Property="BorderWidth" Value="3"/>
<Setter Property="BorderColor" Value="DarkBlue"/>
</VisualState.Setters>
</VisualState>
<VisualState Name="Pressed">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="LightCoral" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Button
Text="Click me"
HorizontalOptions="Fill" >
</Button>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Если посмотреть на этот пример внимательно, то можно заметить, что в стиле мы вместо свойства VisualStateManager.VisualStateGroups использовали объект типа Setter в котором и указали свойство менеджера визуальных состояний
<Setter Property="VisualStateManager.VisualStateGroups">
В остальном же код остался неизменным. Можно запустить приложение и убедиться, что кнопка также реагирует изменением своего внешнего вида на три состояния.
Визуальные состояния доступные по умолчанию в .NET MAUI
Ниже представлены доступные по умолчанию визуальные состояния в .NET MAUI для различных элементов управления:
| Элемент управления | Доступные состояния |
VisualElement |
Normal, Disabled, Focused и PointerOver |
CarouselView |
DefaultItem, CurrentItem, PreviousItem и NextItem |
(информация об элементе) |
Pressed |
CheckBox (информация об элементе) |
IsChecked |
CollectionView |
Selected |
ImageButton (информация об элементе) |
Pressed |
RadioButton (информация об элементе) |
Checked (элемент выбран) и Unchecked (элемент не выбран) |
Switch (информация об элементе) |
On (включено) и Off(выключено) |
Это означает, например, что так как кнопка Button — это наследник VisualElement, то для этого элементу управления мы можем использовать по умолчанию следующие состояния: Normal, Disabled, Focused, PointerOver и Pressed.
Определение собственных состояний элемента
При необходимости, мы можем определять свои визуальные состояния элементов управления. Например, мы можем определить визуальное состояние элемента Entry в зависимости от введенного пользователем значения. Для активации визуального состояния элемента мы должны в каком-либо месте кода C# сделать возов следующего метода:
public static bool GoToState(FrameworkElement control, string stateName);
Первый параметр — элемент управления к которому необходимо применить визуальное состояние, а второй — имя состояния (чувствительно к регистру).
Например, напишем следующий код страницы MainPage.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Vsm.MainPage">
<ScrollView>
<VerticalStackLayout
Padding="30,0"
Spacing="25">
<Entry x:Name="NumberOnly" TextChanged="Entry_TextChanged">
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup Name="EntryStates">
<VisualState Name="Valid">
<VisualState.Setters>
<Setter Property="Background" Value="LightGreen" />
<Setter Property="TextColor" Value="DarkGreen"/>
</VisualState.Setters>
</VisualState>
<VisualState Name="Invalid">
<VisualState.Setters>
<Setter Property="Background" Value="LightCoral" />
<Setter Property="TextColor" Value="DarkRed"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
</Entry>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Здесь мы определили элемент Entry (текстовое поле) у которого определили два состояния — Valid и Invalid. У текстового поля определен обработчик события TextChanged, который выглядит следующим образом:
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
if (int.TryParse(e.NewTextValue, out int value))
{
if (VisualStateManager.GoToState(NumberOnly, "Valid") == false)
throw new Exception("Error");
}
else
{
VisualStateManager.GoToState(NumberOnly, "Invalid");
}
}
Здесь мы проверяем, что ввел пользователь — целое число или просто строку и в зависимости от этого выбираем то или иное состояние. В работающем приложении компонент будет выглядеть следующим образом:
при вводе числа
при вводе строки
Итого
Использование менеджера визуальных состояний (Visual State Manager) позволяет определить стиль оформления элемента в зависимости от того в каком состоянии он находится. В .NET MAUI предусмотрены стандартные состояния элементов, например, Focused, Disabled и т.д. Также мы можем определять собственные состояния элементов управления и применять их.

