Статьи

Поведение WinRT для запуска раскадровки на событии

Иногда я немного отвлекаюсь. В этой статье я упоминаю написанное мной поведение, которое запускает раскадровку события, я даже помещаю в библиотеку win8nl, а затем полностью забываю об этом писать в блоге или даже объявляю об этом. Так или иначе, когда Дэнни ван Нейгхем спросил меня о проблеме, которая была почти решена моим поведением, я как бы вспомнил об этом, и что я полностью забыл об этом — и решил а) улучшить ее и б) поговорить об этом (хорошо, записывать).

Мир, познакомься с StartStoryboardBehavior. Это очень простое поведение, которое имеет следующие свойства:

Раскадровка Название раскадровки для начала. Обязательное.
StartImmediately true = не ждать начала события, просто запустите раскадровку, когда поведение загружено. По желанию; по умолчанию ложь
Название события Событие AttachedObject, которое инициирует начало раскадровки (например, «Нажатие» на кнопке). Игнорируется, когда StartImmediately == true, в противном случае обязательно
SearchTopDown Необязательно, по умолчанию установлено значение true. Если true, поведение начнет поиск вашей раскадровки с вершины визуального дерева. Это сценарий, в котором, например, нажатие кнопки инициирует раскадровку, которая находится где-то в верхней части страницы. Если это значение установлено в false, поведение будет искать от присоединенного объекта вверх. Выберите этот параметр, когда используете поведение для запуска раскадровки, которая находится внутри шаблона.

«SearchTopDown» был добавлен только сейчас, и я надеюсь, что это решит проблему Дэнни. Для тех, кто просто хочет использовать поведение: Nuget Win8nl, и у вас есть поведение готово и готово. Я уже обновил пакет с улучшенным поведением. Для тех, кто хочет учиться — ну, это не ракетостроение, а продолжение.

Первая часть не так уж интересна — просто ваша базовая настройка поведения, подключение и отключение событий. В AssociatedObjectLoaded происходят только интересные вещи:

using System;
using System.Linq;
using Windows.UI.Xaml;
using WinRtBehaviors;
using System.Reflection;
using Win8nl.External;
using Windows.UI.Xaml.Media.Animation;
using System.Reactive.Linq;

namespace Win8nl.Behaviors
{
  public class StartStoryboardBehavior : Behavior<FrameworkElement>
  {
    protected override void OnAttached()
    {
      base.OnAttached();
      AssociatedObject.Loaded += AssociatedObjectLoaded;
    }
    
    protected override void OnDetaching()
    {
      AssociatedObject.Loaded -= AssociatedObjectLoaded;
      base.OnDetaching();
    }

    private void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
    {
      if (StartImmediately)
      {
        StartStoryboard();
      }

      if (!string.IsNullOrWhiteSpace(EventName))
      {
        var evt = AssociatedObject.GetType().GetRuntimeEvent(EventName);
        if (evt != null)
        {
          Observable.FromEventPattern<RoutedEventArgs>(AssociatedObject, EventName)
            .Subscribe(se => StartStoryboard());
        }
      }
    }
  }
}

Если StartImmediately — true, раскадровка запускается немедленно. Если нет, то поведение пытается найти событие с именем, указанным в свойстве EventName, и пытается подключить к нему динамический обработчик, используя Rx. Ничего нового здесь, я уже описывал эту технику ранее — в статье, где я объявил об этом забытом поведении 🙂

Более интересным является этот забавный маленький метод, это в основном одно большое утверждение Linq:

private Storyboard GetStoryBoardInVisualDescendents(FrameworkElement f)
{
  return f.GetVisualDescendents()
    .Where(p => p.Resources.ContainsKey(Storyboard) && p.Resources[Storyboard] is Storyboard)
    .Select(p => p.Resources[Storyboard] as Storyboard).FirstOrDefault();
}

Он проверяет все визуальные детские ресурсы на раскадровку с именем, указанным в «Раскадровке», и, если так, выбирает ее. Он использует метод расширения GetVisualDescendents для генерации списка всех дочерних элементов — вплоть до нижней части визуального дерева от элемента в «f».

Что касается поведения по умолчанию (meh), оно ищет раскадровку сверху вниз, используя этот метод:

private void StartStoryboardTopDown()
{
  var root = AssociatedObject.GetVisualAncestors().Last() ?? AssociatedObject;

  var storyboard = GetStoryBoardInVisualDescendents(root);
  if (storyboard != null)
  {
    storyboard.Begin();
  }
}

В двух словах: найдите самый последний верхний объект в визуальном дереве — это корень. Если это ноль, очевидно, что текущий связанный объект уже является корнем. Затем он начинает искать раскадровку и, если найдет ее, запустит.

Для стратегии снизу вверх используется другой метод с очень оригинальным названием:

private void StartStoryboardBottomUp()
{
  var root = AssociatedObject;
  Storyboard storyboard;
  do
  {
    storyboard = GetStoryBoardInVisualDescendents(root);
    if (storyboard == null)
    {
      root = root.GetVisualParent();
    }
  } while (root != null && storyboard == null);

  if (storyboard != null)
  {
    storyboard.Begin();
  }
}

Этот метод начинается с попытки найти раскадровку в визуальном дереве под текущим связанным объектом. Если он не находит его, он перемещается на один уровень вверх и пытается снова. И еще один. Пока) а) не находит раскадровку или б) не хватает уровней. Если раскадровка найдена, она запускается. Хорошо, это немного неэффективно, но это происходит только после запуска мероприятия.

Последними частями головоломки является StartStoryboard, которая просто выбирает метод на основе значения SearchTopDown.

private void StartStoryboard()
{
  if( SearchTopDown)
  {
    StartStoryboardTopDown();
  }
  else
  {
    StartStoryboardBottomUp();
  }
}

И это все, что нужно сделать. Я пропустил объявление четырех свойств (вложенных зависимостей), так как оно только заполняет этот пост без фактического значения, и полный список можно найти здесь, в CodePlex, если это поможет вам получить обзор.

Screenshot8Для тех, кто любит наблюдать за поведением в действии, я создал небольшой пример приложения , в котором показано несколько элементов в ListBox. В конце каждой строки есть кнопка, и если вы нажмете, цвет трех текстов слева будет анимирован с черного на красный примерно за секунду. Это раскадровка, запускаемая поведением. Очень волнующий 😉 — но это доказывает суть.

Наслаждайтесь! Надеюсь, это поможет вам в разработке Windows 8 ! Глобальная доступность наступает, получите взломать, чтобы получить свои вещи в магазине!