Поехали!
Давайте посмотрим, на пример поведения, из
предыдущего сообщения:
<Rectangle Fill="Green" Width="40" Height="40" x:Name="rct"> <i:Interaction.Behaviors> <local:DragBehavior/> </i:Interaction.Behaviors> </Rectangle>
Класс Interaction определяет присоединенное свойство (Attached Property) типа
BehaviorCollection:
Последний штрих: мы не можем напрямую унаследоваться от класса Behavior (у него internal конструктор). Вместо этого нам предлагают воспользоваться обобщенным классом Behavior<T>, где T - DependencyObject.
Почему на T накладывается ограничение - быть DependencyObject'ом понятно: attached property можно прикрепить только к DependencyObject'у. Но почему же мы не можем напрямую унаследоваться от Behavior? Зачем делать конструктор внутренним? - Для нашего же блага :).
Например, мы захотим написать поведение применимое только к панелям. Вместо того, чтобы ходить каждый раз после крэша в Graphic Design Department, и объяснять дизайнерам: "Пожалуйста, не перетаскивайте поведение с названием OnlyForPanelsBehavior, на кнопки - это сломает систему", мы просто наследуемся от Behavior<Panel>, и Blend не даст перетянуть поведение на кого-то, отличного от Panel'a :). Удобно, не так ли?
BehaviorsProperty = DependencyProperty.RegisterAttached( "Behaviors", typeof (BehaviorCollection), typeof (Interaction), new PropertyMetadata(new PropertyChangedCallback(Interaction.OnBehaviorsChanged)) );Когда мы прикрепляем к некоторому объекту это свойство, в рамках нашего класса-сервиса Interaction, вызывается метод OnBehaviorsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args). Первым параметром этого метода будет объект, к которому мы присоединили attached property, а во втором мы найдем список определенных поведений. (В нашем примере: obj == прямоугольник rct, а args.NewValue == коллекция, с одним элементом DragBehavior). Имея эти два козыря на руках, класс Interaction, в методе OnBehaviorsChanged() проходится по коллекции поведений, и у каждого из поведений вызывает метод Attach(), передавая объект, к которому был присоединен attached property:
//... Где-то в OnBehaviorsChanged() foreach (Behavior behavior in behaviorsCollection) { behavior.Attach(obj); }Дальше остается дело за малым: базовый класс Behavior устанавливает свое свойство AssociatedObject в переданный ему obj, и вызывает виртуальный метод OnAttached(), чтобы известить своих наследников о произошедшем соединении :). Именно этот метод мы использовали в примере из прошлого поста, чтобы подписаться на события от мышки.
public class DragBehavior : Behavior<UIElement> { protected override void OnAttached() { AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown; AssociatedObject.MouseMove += AssociatedObject_MouseMove; AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp; } // ... }
Последний штрих: мы не можем напрямую унаследоваться от класса Behavior (у него internal конструктор). Вместо этого нам предлагают воспользоваться обобщенным классом Behavior<T>, где T - DependencyObject.
Почему на T накладывается ограничение - быть DependencyObject'ом понятно: attached property можно прикрепить только к DependencyObject'у. Но почему же мы не можем напрямую унаследоваться от Behavior? Зачем делать конструктор внутренним? - Для нашего же блага :).
Например, мы захотим написать поведение применимое только к панелям. Вместо того, чтобы ходить каждый раз после крэша в Graphic Design Department, и объяснять дизайнерам: "Пожалуйста, не перетаскивайте поведение с названием OnlyForPanelsBehavior, на кнопки - это сломает систему", мы просто наследуемся от Behavior<Panel>, и Blend не даст перетянуть поведение на кого-то, отличного от Panel'a :). Удобно, не так ли?
Что дальше?
Айда писать классные, потрясающие и просто захватывающие поведения :)!
Поделиться своим произведением всегда можно на сайте
Microsoft Expression Gallery.
К сожалению, мой обзор поведений остается неполным без Trigger'ов и Action'ов. В ближайшем будущем (на следующей неделе) я собираюсь избавиться от этого пробела :).
Отличного программирования, друзья!
К сожалению, мой обзор поведений остается неполным без Trigger'ов и Action'ов. В ближайшем будущем (на следующей неделе) я собираюсь избавиться от этого пробела :).
Отличного программирования, друзья!
Flenger
ОтветитьУдалитьОчень классно пишешь, аж приятно читать.
Респект!