В предыдущем посте я рассказал о двух новых возможностях Visual State Manager’a: Setter’ах и адаптивных триггерах. Как вы увидели — адаптивные триггеры ограничивается только размером экрана, т.е. для других необходимых целей применить их не получится. Но в реальных приложениях вам может потребоваться менять свой интерфейс на основе множества различных параметров, таких как Xbox контроллер, ориентация экрана, наличия данных и т.д. Таким образом, в этой статье я хочу показать, как продлить существующую инфраструктуру адаптивных триггеров, создав свой собственный.
Трудно найти приложение, которое не подключен к Интернету. Но получение данных из занимает некоторое время. Обычно я использую ProgressRing, что бы показать, что получение данных продолжается и я использую VisualStateManager, чтобы показать или скрыть элементы, основанные на имеющихся данных. Обычно есть три состояния: загрузка, загружено и ошибка. Естественно будет необходимо реализовать некоторый код, который изменит состояние приложения на основе состояния «модели представления». Давайте посмотрим, может ли мы вообще реализовывать свои собственные триггеры и поможет ли нам это в избежании создания лишнего кода.
Прежде всего, мы должны проверить, готов ли наш класс «вьюмодели» к использованию вместе с триггерами. Лучше всего реализовать свойство, которое показывает текущее состояние, а также событие, которое срабатывает каждый раз при изменении данного свойства. Конечно, лучше всего это реализовать в базовом классе.
public enum StateEnum { Loading, Loaded, Error } public class StateChangeEventArgs:EventArgs { public StateEnum State { get; set; } } public delegate void StateChangedDelegate(object model, StateChangeEventArgs args); public class PageViewModel { public event StateChangedDelegate StateChanged; public void InitModel() { if (StateChanged != null) StateChanged.Invoke(this, new StateChangeEventArgs() { State = StateEnum.Loading }); //load data if (StateChanged != null) StateChanged.Invoke(this, new StateChangeEventArgs() { State = StateEnum.Loaded }); } }
Метод InitModel выступает примером того, как можно вызывать и работать с этим функционалом.
После окончания работы над вбюмоделью можно создать ее экземпляр на странице.
<Page.Resources> <st:PageViewModel x:Name="model"></st:PageViewModel> </Page.Resources>
Самое время для создания собственного триггера. Для этого вы должны создать новый класс, который будет наследовать класс StateTriggerBase. Внутри класса можно объявить любые методы и свойства, но вы должны помнить, что вам будет необходимо вызывать метод SetActive. Благодаря ему можно активировать или деактивировать свой триггер. Например, я реализовал следующий класс:
public class DataTrigger: StateTriggerBase { private PageViewModel model; public PageViewModel Model { get { return model; } set { model = value; model.StateChanged += Model_StateChanged; } } public string StateOfModel { get; set; } private void Model_StateChanged(object model, StateChangeEventArgs args) { SetActive(args.State.ToString().Equals(StateOfModel)); } }
Как вы можете видеть у меня есть два свойства, которые позволяют установить ссылку на текущую вьюмодель и определить состояние, которое мы будем использовать для активации триггера. После того, как вьюмодель инициализируется — мы активируем или деактивируем триггер с помощью обработчика события StateChanged.
В итоге у меня получились следующие состояния в XAML:
<VisualState x:Name="Loading"> <VisualState.Setters> <Setter Target="gridView.Visibility" Value="Collapsed"></Setter> <Setter Target="progress.Visibility" Value="Visible"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <st:DataTrigger Model="{StaticResource model}" StateOfModel="Loading"></st:DataTrigger> </VisualState.StateTriggers> </VisualState> <VisualState x:Name="Loaded"> <VisualState.Setters> <Setter Target="gridView.Visibility" Value="Visible"></Setter> <Setter Target="progress.Visibility" Value="Collapsed"></Setter> </VisualState.Setters> <VisualState.StateTriggers> <st:DataTrigger Model="{StaticResource model}" StateOfModel="Loaded"></st:DataTrigger> </VisualState.StateTriggers> </VisualState>
Ссылка на источник: UWP: New features of Visual State Manager (part 2)
Пишет «префикс пространства имён «st» не определён»
Отбой. Разобрался. Пробелы в знаниях xaml 🙂