Визуальные состояния
Диспетчер визуальных состояний .NET Multi-platform App Manager (.NET MAUI) предоставляет структурированный способ внесения визуальных изменений в пользовательский интерфейс из кода. В большинстве случаев пользовательский интерфейс приложения определен в XAML, и этот XAML может включать разметку, описывающую, как диспетчер визуальных состояний влияет на визуальные элементы пользовательского интерфейса.
Диспетчер визуальных состояний представляет концепцию визуальных состояний. Представление .NET MAUI, например представление Button может иметь несколько различных внешних представлений визуального элемента в зависимости от его базового состояния — отключается ли он или нажимается или имеет фокус ввода. Это состояния кнопки. Визуальные состояния собираются в группах визуальных состояний. Все визуальные состояния в группе визуальных состояний являются взаимоисключающими. Визуальные состояния и группы визуальных состояний определяются простыми текстовыми строками.
Диспетчер визуальных состояний .NET MAUI определяет группу визуальных состояний, именуемую CommonStates
следующими визуальными состояниями:
- Обычная
- Выключено
- Режим фокусировки
- Выбрано
- PointerOver
Состояния Normal
, Disabled
Focused
и PointerOver
визуальные состояния поддерживаются во всех классах, производных от VisualElement, который является базовым классом для View и Page. Кроме того, можно также определить собственные группы визуальных состояний и визуальные состояния.
Преимущество использования визуального диспетчера состояний для определения внешнего вида, а не доступа к визуальным элементам непосредственно из кода за пределами кода, заключается в том, что визуальные элементы реагируют на другое состояние в XAML, который сохраняет весь дизайн пользовательского интерфейса в одном расположении.
Примечание.
Триггеры также могут вносить изменения в визуальные элементы в пользовательском интерфейсе на основе изменений в свойствах представления или срабатывании событий. Однако использование триггеров для работы с различными сочетаниями этих изменений может стать запутанным. С помощью диспетчера визуальных состояний визуальные состояния в группе визуальных состояний всегда являются взаимоисключающими. В любое время только одно состояние в каждой группе — текущее состояние.
Распространенные визуальные состояния
Диспетчер визуальных состояний позволяет включить разметку в 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 объектов. Это те же Setter объекты, которые используются в объекте Style . Setters
не является свойством содержимого VisualState, поэтому необходимо включить теги элементов свойства для Setters
свойства. Setter Объекты должны вставляться в виде дочерних Setters
объектов. Каждый Setter объект указывает значение свойства при текущем состоянии. Любое свойство, на которое Setter ссылается объект, должно поддерживаться привязываемым свойством.
Внимание
Чтобы объекты визуального Normal
состояния Setter функционировали правильно, VisualStateGroup
должен содержать VisualState объект для состояния. Если у этого визуального состояния нет 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 фон становится светло-синий. Так как диспетчер визуальных состояний переключается между визуальными состояниями, свойства, заданные предыдущим состоянием, не заданы. Таким образом, визуальные состояния являются взаимоисключающими.
Если вы хотите 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
свойства. Свойство содержимого для Setter объекта является его Value
свойством, поэтому его можно указать как дочерний 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
При определении свойства задает Property
объект, Setter определенный в TargetName
Value
:
<Setter TargetName="label"
Property="Label.TextColor"
Value="Red" />
В этом примере у именованного Label label
свойства будет TextColor
задано значение Red
. При задании TargetName
свойства необходимо указать полный путь к свойству.Property
Таким образом, чтобы задать TextColor
свойство в объекте Label, Property
указывается как 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 отображает любой ранее введенный текст.
Внимание
Пути свойств не поддерживаются в Setter элементах, которые указывают TargetName
свойство.
Определение настраиваемых визуальных состояний
Пользовательские визуальные состояния можно реализовать, определив их так же, как вы определите визуальные состояния для общих состояний, но с именами выбранных состояний, а затем вызовом 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и есть два взаимоисключающих состояния с именем Valid
и Invalid
. Entry Если номер телефона не содержит допустимый, то текущее состояние Invalid
равно, и поэтому Entry имеется розовый фон, второй Label отображается и Button отключен. При вводе допустимого номера телефона текущее состояние становится Valid
. Получает Entry фон лайма, второй Label исчезает и Button теперь включен:
Файл программной части отвечает за обработку TextChanged
события из файла Entry. Обработчик использует регулярное выражение, чтобы определить, является ли входная строка допустимой или нет. Метод GoToState
в файле программной части вызывает статический VisualStateManager.GoToState
метод объекта StackLayout :
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 .
Триггеры состояния добавляются в коллекцию StateTriggers VisualState. Эта коллекция может содержать один или несколько триггеров состояния. При наличии активных триггеров состояния в коллекции будет применяться VisualState.
При использовании триггеров состояния для управления визуальными состояниями .NET MAUI использует следующие правила приоритета, чтобы определить, какой триггер (и соответствующий VisualState) будет активным:
- Любой триггер, производный от StateTriggerBase.
- AdaptiveTrigger активируется из-за выполнения условия MinWindowWidth.
- AdaptiveTrigger активируется из-за выполнения условия MinWindowHeight.
Если одновременно активны несколько триггеров (например, два пользовательских триггера), то у первого триггера, объявленного в разметке, будет приоритет.
Дополнительные сведения о триггерах состояния см. в разделе Триггеры состояния.