Создание поведений
89WPF --- Привязка, команды и стили WPF --- Создание поведений
Поведения служат для инкапсуляции частей функциональности пользовательского интерфейса, чтобы их можно было применять к элементам без написания соответствующего кода вручную. По-другому поведение можно рассматривать как службу, предлагаемую для элементов. Эта служба обычно предусматривает прослушивание нескольких различных событий и выполнение множества связанных операций.
Наилучшим способом получить представление о поведениях предусматривает создание собственного поведения. Предположим, что необходимо предоставить любому элементу возможность перетаскивания с помощью мыши в рамках контейнера Canvas. Основные шаги для обеспечения такой возможностью единственного элемента довольно просты: код прослушивает события мыши и изменяет присоединенные свойства, которые соответствующим образом устанавливают координаты элемента Canvas. Приложив еще немного усилий, этот код можно превратить в многократно используемое поведение, которое будет снабжать поддержкой перетаскивания любой элемент в любом контейнере Canvas.
Прежде всего, создайте сборку библиотеки классов WPF (для настоящего примера подойдет имя CustomBehaviorsLibrary) и добавьте в ней ссылку на сборку System.Windows.Interactivity.dll. Затем создайте класс, унаследованный от Behavior — обобщенного класса, который принимает аргумент типа. Можно использовать либо этот аргумент типа для ограничения области действия поведения определенными элементами, либо UIElement или FrameworkElement для охвата всех элементов, как показано ниже:
public class DragInCanvasBehavior : Behavior<UIElement>
{
private Canvas canvas;
protected override void OnAttached()
{
base.OnAttached();
// Присоединение обработчиков событий
this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
}
protected override void OnDetaching()
{
base.OnDetaching();
// Удаление обработчиков событий
this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
}
// Отслеживание перетаскивания элемента
private bool isDragging = false;
// Запись точной позиции, в которой нажата кнопка
private Point mouseOffset;
private void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Поиск canvas
if (canvas == null) canvas = VisualTreeHelper.GetParent(this.AssociatedObject) as Canvas;
// Режим перетаскивания
isDragging = true;
// Получение позиции нажатия относительно элемента
mouseOffset = e.GetPosition(AssociatedObject);
// Захват мыши
AssociatedObject.CaptureMouse();
}
private void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
// Получение позиции элемента относительно Canvas
Point point = e.GetPosition(canvas);
// Move the element.
AssociatedObject.SetValue(Canvas.TopProperty, point.Y - mouseOffset.Y);
AssociatedObject.SetValue(Canvas.LeftProperty, point.X - mouseOffset.X);
}
}
private void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (isDragging)
{
AssociatedObject.ReleaseMouseCapture();
isDragging = false;
}
}
}
Первым шагом при создании любого поведения является переопределение методов OnAttached() и OnDetaching(). В методе OnAttached() можно получить доступ к элементу, в котором размещено поведение (через свойство AssociatedObject), и присоединить обработчики событий. В методе OnDetaching() можно удалить эти обработчики событий.
Последним шагом является помещение нужного кода в обработчики событий. Например, когда пользователь нажимает левую кнопку мыши, поведение DragInCanvasBehavior начинает операцию перетаскивания, сохраняет смещение между левым верхним углом элемента и курсором мыши и захватывает мышь.
Когда элемент находится в режиме перетаскивания, а мышь перемещается, позиция элемента должна изменяться (обработчик AssociatedObject_MouseMove). И, наконец, при отпускании кнопки мыши операция перетаскивания должна быть завершена (метод AssociatedObject_MouseLeftButtonUp).