Недавно нашей командой (Sly Lamb) был выпущен клиент для сервиса Pruffi.ru под Windows Phone. Во время разработки у нас возник вопрос – как отображать пользователю список вакансий, который может находиться в нескольких состояниях.

В этой статье мы хотим показать легкий механизм изменения состояния отображения элементов при помощи Expression Blend и паттерна MVVM. Пример будет приведен с использованием фреймворка MVVM Light Toolkit, но думаю, различия с другими должны быть минимальны.

Для чего это нужно?


Итак, на панораме есть список вакансий. Он может загружаться, быть пуст, или отображаться. Первые два состояния можно объединить в одно визуальное – это вывод сообщения. Итого два состояния: показать список, показать сообщение.

Но как показать сообщение? Нехорошо пугать человека стандартными MessageBox-ами. Тогда, ориентируясь на стандартные приложения, мы решили убирать все элементы, и выводить сообщение на месте элементов. Мы поступили так же, как на скриншотах.


Как реализовать?


Первое, что приходит в голову, манипулировать свойствами Visiblity у всех элементов, в зависимости от состояния. Такой подход громоздкий, так как для переключения из одного состояния в другой надо будет написать функцию по скрытию и отображению нужных элементов, плюс надо будет самим инициировать эту функцию при нужных условиях.

Для данного случая Expression Blend приготовил нам удобный инструмент, это State(состояния) для каждого элемента, а также поведение DataStateBehavior.

State – это визуальное состояние элемента относительно базового, в котором хранятся параметры самого элемента и дочерних, такие как цвета, положения, прозрачность и т. д.


DataStateBehavior – это поведение, которое переключает между двумя State, в зависимости от условия. Если привязанный параметр совпадает со значением Value, тогда используется TrueState, если не совпадает, тогда FalseState.


Как использовать?


Приведу небольшой пример, в котором создаются и переключаются по времени два состояния.

Создаем пустой проект, используя шаблон MvvmLight (WP71).
Шаблон входит в состав MVVM Light Toolkit.

Сразу создадим логику во ViewModel страницы MainPage. Добавим свойство, которое будет меняться каждые пять секунд с текста «ok» на «hello world».

Откроем MainViewModel.cs и создадим там свойство MessageText:
public const string MessageTextPropertyName = "MessageText";
private string _messageText = "ok";

public string MessageText
{
  get { return _messageText; }

  set
      {
        if (_messageText == value)
                    return;

        _messageText = value;
        RaisePropertyChanged(MessageTextPropertyName);
       }
}

Чтобы свойство менялось каждые пять секунд, добавим в конструктор класса MainViewModel код:
//создаем таймер
var dispatcherTimer = new System.Windows.Threading.DispatcherTimer();

//устанавливаем действие при каждом тике таймера
dispatcherTimer.Tick += ((a,b) =>
                     {
                         MessageText = MessageText == "ok" ? "hello world" : "ok";
                     });

//определяем интервал между тиками
dispatcherTimer.Interval = new TimeSpan(0, 0, 5);

//запускаем таймер
dispatcherTimer.Start();

Перейдем к дизайну страницы, для этого откроем проект в Expression Blend.

Добавим на MainPage кнопку и текстовый блок. Кнопку будем отображать, когда свойство MessageText равно «ok», во всех остальных случаях отображаем текстовое поле с содержимым MessageText.

Замечу, что кнопка играет роль контента страницы, а текстовое поле – некритичной ошибки или сообщения, при котором контент показывать нельзя или он пуст.
После добавления форма будет выглядеть примерно так.


К значению Text элемента TextBlock привязываем наше свойство MessageText, нажав на квадрат справа от свойства и выбрав пунк DataBinding. В открывшемся окне нужно выбрать нужное свойство и нажать «OK».


Перейдем к созданию состояний. Откройте вкладку States в панели, которая находиться в левом верхнем углу экрана. Нажмите в ней кнопку Add state group. Выберите состояние Base – это то, от которого буду отталкиваться все остальные.


Измените, свойство Visibility у текстового поля на Collapsed, чтобы оно пропало.

Нажмите справа у группы состояний VisualStateGroup кнопу Add State, чтобы создать состояние с название Normal, а затем c названием Message.


Состояние Normal оставим, т.к. оно должно быть таким же, как и Base. А состояние Message запишем, нажав на него. Должно появиться сообщение о записи как на скриншоте. После чего изменим свойство Visiblity у кнопки на Collapsed, а у текстового блока на Visiblity. Для завершения записи нажмите на одну из красных кнопок.

Состояния созданы, осталось добавить переключатель между ними. Для этого добавим на страницу DataStateBehavior из вкладки Assets в категории Behaviors.

Свойство Binding привязываем к свойству MessageText, значение Value выставляем в «ok». Состояние TrueState ставим Normal, а FalseState ставим Message. Запускаем приложение и видим, как меняется состояние страницы в зависимости от значения поля MessageText.


Также можно добавлять анимацию между состояниями или простые переходы через свойство Default transition в VisualStateGroup.

Еще хочется обратить ваше внимание на GoToStateAction, который умеет переходить на состояние при каком-либо действии, например при нажатии на кнопку.

На этом все, комментируйте, буду рад ответить на ваши вопросы.

Исходный код: скачать/посмотреть