Давным-давно я писал, как управлять анимацией из вашей ViewModel, используя DataStateBehavior , и я прямо заявил, что это единственный способ сделать это, поскольку (цитируя себя), «Windows Phone 7 не поддерживает DataTriggers ». Это было тогда, а это сейчас. Недостаток DataStateBehavior заключается в том, что вы в основном можете выполнять только анимацию включения / выключения, что делает невозможной более сложную анимацию с несколькими состояниями. Было другое поведение, которое могло сделать это, но я не мог найти это больше, и я не мог вспомнить имя. А потом я неожиданно наткнулся на сборку Microsoft.Expression.Interactions — и в ее пространстве имен Microsoft.Expression.Interactions.Core действительно есть DataTrigger. И это, кажется, присутствовало в структуре 7.1. *Кашель*.
Итак, в этом посте я собираюсь продемонстрировать, как анимировать несколько «всплывающих окон» через один блок Visual State и ViewModel, используя DataTriggers. Я собираюсь показать это, используя Visual Studio 2012, MVVMLight и в основном Blend. Пришло время снова подарить этому невоспетому герою немного любви, поэтому я собираюсь снова следовать стилю обучения.
- Откройте Visual Studio, создайте « приложение для Windows Phone » и нацеливайте на 8.0 (это должно работать и в 7.1, кстати)
- Нажмите Инструменты / Диспетчер пакетов библиотеки / Управление пакетами NuGet для решения.
- Найдите MvvmLightLibs, выберите «Только легкие библиотеки MVVM»
- Нажмите «Установить», «ОК» и «Я принимаю»
Построение ViewModel
Фактически ViewModel состоит из двух файлов — перечисления, описывающего состояния и самого ViewModel. Сначала создайте папку «ViewModel» в своем решении, и создайте перечисление следующим образом:
namespace DataTriggerAnimation.ViewModel { public enum DisplayState { Normal = 0, ShowPopupHello = 1, ShowPopupBye = 2, } }
И тогда ViewModel, как это:
using System; using System.Windows.Input; using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Command; namespace DataTriggerAnimation.ViewModel { public class DisplayViewModel : ViewModelBase { private DisplayState displayState; public DisplayState DisplayState { get { return displayState; } set { if (displayState != value) { displayState = value; RaisePropertyChanged(() => DisplayState); } } } public ICommand DisplayPopupCommand { get { return new RelayCommand<string>( (p) => { DisplayState = (DisplayState)Enum.Parse(typeof(DisplayState), p); }); } } public ICommand CloseCommand { get { return new RelayCommand(() => DisplayState = DisplayState.Normal); } } } }
Важно отметить, что команда «DisplayPopupCommand» требует параметр для определения всплывающего окна, которое должно отображаться. Команда CloseCommand эквивалентна команде DisplayPopupCommand с параметром «Normal» и предназначена для облегчения жизни дизайнера.
… и это все кодирование, которое мы собираемся сделать. Создайте свое приложение и закройте Visual Studio. Все остальное, как и мой последний анимационный пост, сделано в Blend! Все это
Создание первой панели
- Перетащите сетку на пустой прямоугольник «ContentPanel». Как и все объекты с графическим интерфейсом, их можно найти на вкладке «Активы» в левой верхней части.
- Нажмите на «Сетка» на левой панели «Объекты на временной шкале» и переименуйте ее в «Panel1».
- Щелкните правой кнопкой мыши на сетке «Panel1», нажмите «Сбросить макет / Все»
- Перейдите на правую панель, выберите «Свойства» и раскройте панель «Макет», если она свернута.
- Затем нажмите «Верх» для вертикального выравнивания.
- Затем введите «150» для высоты
Затем добавьте текст:
- Перетащите TextBlock на сетку «Panel1». Это можно сделать, перетащив его на поверхность конструктора в верхней части «Panel1» или на панель «Объекты и временная шкала» (также поверх «Panel1»).
- Измените текст с «TextBlock» на «Здравствуйте, это всплывающее окно»
- Сделайте Reset Layout / All по этому тексту, а также
- На панели макетов выберите горизонтальное выравнивание «Центр» и вертикальное выравнивание «Верх»
И наконец добавьте кнопку:
- Перетащите кнопку на Panel1
- Сделайте Reset Layout / All также на этой кнопке
- Измените заголовок на «Готово»
- На панели макетов выберите Горизонтальное выравнивание «Центр» и Вертикальное выравнивание «Низ»
А потом, наконец, сделайте что-то, что кажется симпатичным помешанным, но поверьте мне: все станет ясно в конце:
- Выберите Panel1 на панели «Объекты и временная шкала».
- Перейдите на панель свойств с правой стороны и найдите панель «Преобразование». Обычно это рухнуло. Раскройте это сначала.
- Выберите вкладку «Центральная точка» — 2-я вкладка справа под «Rendertransform» (с точкой в)
- Для X и Y введите «0,5». Это устанавливает точку трансформации мертвой в середине панели
- Затем также выберите вкладку «Глобальное смещение» — это вторая вкладка справа под «Проекция» (со стрелкой вверх и влево на ней)
- Введите «500» для X.
Ваша дизайнерская поверхность должна выглядеть так, как показано справа. Панель хорошо сидит справа от телефона. Бонкерс, я это сказал. ;-).
Создание второй панели
Буду немного ленивым здесь. Я не хочу снова всю последовательность
- Выберите Панель 1 в «Объекты и Временная шкала»
- Нажмите CTRL-C, CTRL-V. Это приведет к Panel1_Copy ниже Panel 1
- Переименуйте это в «Panel2»
- Снова перейдите на вкладку «Свойства» справа и введите «160» для верхнего поля. Это должно привести к появлению Panel2 под Panel1
- Затем, на бис, снова перейдите на панель Transform и измените «500» для X Projection на -500
Вторая панель должна перейти влево, и получившаяся поверхность дизайна теперь должна выглядеть так:
Создание всплывающих кнопок
В настоящее время я предполагаю, что вы теперь понимаете панель макетов, поэтому я не собираюсь делать скриншоты для каждой кнопки, которую нужно нажать, и числа, которое необходимо ввести на панелях макета ?
- Перетащите панель StackPanel на поверхность конструктора в нижней части экрана.
- Сделать сброс макета / все,
- Выберите Вертикальное выравнивание снизу и введите высоту 220.
- Продолжайте перетаскивать три кнопки поверх StackPanel. Они должны появляться друг под другом, занимая всю ширину экрана.
- Измените заголовки кнопок на (сверху вниз) «Popup 1», «Popup 2» и «Done».
Окончательная поверхность проекта, включая дерево объектов, должна выглядеть следующим образом:
Определение визуальных состояний
У нас есть три визуальных состояния:
- Ни одно из всплывающих окон не отображается
- Всплывающее окно 1 отображается
- Всплывающее окно 2 отображается
Чтобы создать их, выполните следующие действия:
- Вверху слева нажмите вкладку «Состояния».
- Нажмите кнопку «Добавить группу состояний»
- Переименуйте «VisualStateGroup» в «PopupGroup»
- Введите «0.5» для «Переход по умолчанию». Это означает, что любые переходы между состояниями будут автоматически анимированы в течение 0,5 секунд.
Следующие шаги:
- Нажмите кнопку «Добавить состояние»
- Переименуйте состояние «VisualState» в «Normal»
- Добавьте еще два состояния, «ShowPopupHello» и «ShowPopupBye»
- Нажмите красную точку перед «ShowPopupBye». Красный цвет исчезает. На главной поверхности дизайна теперь должна быть надпись «Запись состояния ShowPopupBye выключена»
Теперь следующие вещи сложны, поэтому обратите пристальное внимание и убедитесь, что вы делаете это правильно.
- Выберите «Panel1» в «Объектах и шкале времени»
- Нажмите состояние «ShowPopupHello». Основная область дизайна теперь должна иметь надпись «Запись ShowHelloPopupstate включена» и иметь красную рамку.
- Снова перейдите на панель «Преобразование», снова выберите в проекции значение «Глобальное смещение» (2-я вкладка справа) и измените значение 500 на 0. Теперь панель 1 должна появиться на экране телефона.
- Теперь выберите состояние «ShowPopupBye». Панель 1 снова исчезает
- Выберите Panel2
- Также измените его глобальное смещение на 0. Теперь панель 2 появляется на экране телефона
- Выберите состояние «Нормальный»
- Выберите красную точку перед «Normal», чтобы отключить запись состояния. Обе панели теперь снова должны быть за пределами экрана телефона.
- Выберите «База» в верхней части панели состояния.
Ввод в ViewModel
Прежде чем мы собираемся подключить визуальные состояния к действиям ViewModel, давайте сначала внесем это. Это довольно просто.
- Идите в верхнем правом углу и выберите вкладку данных.
- Нажмите кнопку «Создать источник данных» справа и выберите «Создать источник данных объекта».
- Примерно в 8-й строке вы должны увидеть «DisplayViewModel». Выберите это
- Введите «DisplayViewModelDataSource» в поле «Имя источника данных»
- Хит ОК.
- Чистый результат должен быть таким, как показано справа.
Настройка начальной привязки данных
Это так смешно легко в Blend, что всегда радует меня, когда я вхожу в это состояние.
- Перетащите «DisplayViewModel» с вкладки данных в верхней части панели LayoutRoot на панели «Объекты и временная шкала».
- Перетащите «CloseCommand» поверх всех трех кнопок «Done». Вы можете сделать это на панели дизайна или на панели «Объекты и временная шкала», как вам угодно.
- Продолжайте перетаскивать «PopupCommand» поверх кнопок «Popup 1» и «Popup 2».
- Теперь нажмите кнопку «Всплывающее окно 1» и снова выберите вкладку «Свойства».
- Сверху есть поле «Поиск свойств». Вскоре разработчики Blend поняли, какое количество вещей вы можете установить настолько большим, что вы можете легко потерять трек. Введите «Command» в это поле поиска, чтобы ограничить количество отображаемых свойств.
- В окне «Свойства» теперь должны отображаться только «Command» и «CommandParameter». Введите значение «ShowPopupHello» для «CommandParameter»
- Теперь нажмите кнопку «Popup 2» и введите «ShowPopupBye» для «CommandParameter»
- Удалите текст «Команда» в «Свойствах поиска», чтобы снова увидеть все свойства.
Программирование, перетаскивая вещи друг на друга. Разве жизнь не веселая иногда?
Введите дракона: datatriggers для того, чтобы собрать все это вместе
А теперь для действительно страшной части — датгригеры. Шучу, конечно — просто перетаскиваю вещи и заполняю некоторые поля. Странно то, что с точки зрения Blend триггеры данных почти не видны. Мы используем GotoStateActions . Завершите приложение, выполнив следующие заключительные шаги:
- Перетащите поле GotoStateAction из активов поверх ContentPanel. Если вы не можете его найти: введите «goto» в поле поиска на панели «Активы». Он появится в списке справа от панели.
- В разделе «Свойства» нажмите кнопку «Создать» рядом с «TriggerType» и выберите «DataTrigger» в появившемся окне.
- За «Binding», нажмите значок барреля, как. Появится диалоговое окно со свойствами вашей DisplayViewModel. Выберите «DisplayState» и нажмите ОК
- Введите «0» для значения
- Для StateName выберите «Normal»
- Перетащите еще одно действие GotoStateAction из активов в верхней части ContentPanel. Сделайте для этого DataTrigger, выберите то же свойство для привязки, но
- Введите «1» для «Значение»
- Выберите «ShowPopupHello» для StateName
- И, наконец, третье действие GotoStateAction со значением 2 и «ShowPopupBye» для StateName.
And that’s all. If you run your application (you should be able to hit F5 from Blend) you will get a simple app that scrolls Popup 1 from the left in half a second when you hit “Popup 1”, and scroll it back when you hit on of the done buttons. If you hit the “Popup 2” button when Popup 1 is visible, it will scroll the second popup into the screen while simultaneously scrolling the first on out of the screen.
The data triggers look like this in XAML:
<i:Interaction.Triggers> <ec:DataTrigger Binding="{Binding DisplayState}" Value="0"> <ec:GoToStateAction StateName="Normal"/> </ec:DataTrigger> <ec:DataTrigger Binding="{Binding DisplayState}" Value="1"> <ec:GoToStateAction StateName="ShowPopupHello"/> </ec:DataTrigger> <ec:DataTrigger Binding="{Binding DisplayState}" Value="2"> <ec:GoToStateAction StateName="ShowPopupBye"/> </ec:DataTrigger> </i:Interaction.Triggers>
Some things to note
- We hardly did program anything at all, and what’s more – we did not even make animations or storyboards. By simply setting the default transition to 0.5 seconds and indicating where we want stuff to be once a state is reached, the Windows Phone framework automatically infers and creates an animation when changing state, moving the GUI elements from one place to another in half a second (in stead of flashing them from one place to another).
- In the Command I was able to use names as defined in the enumeration because I did an Enum.Parse in the ViewModel, in the data triggers I had to use the real value (0,1,2) to be able to compare. Something that can be fixed using a converter, but I did not want to complicate things.
- The fact that the visual state names have the same name as the enumeration values, does not bear any significance. I could have named them Huey, Dewey, and Louie for all I cared. Only the CommandParameter values need to be the same as the Enumeration string, and the DataTriggers need to have the same numeric value.
That’s it. Although the Visual Studio 2012 designer is light years ahead of the 2010 designer, Blend still rocks when defining a lot of stuff in XAML. Have fun making beautifully animated apps with this.
If you don’t feel like following all these steps yourself, find, as usual, the completed solution here.