WP7 - перетаскивание объектов, созданных из DataTemplate в Canvas - PullRequest
2 голосов
/ 01 февраля 2011

Краткий обзор:
Мое приложение отображает ItemsControl, содержащий Canvas в качестве ItemsPanel. ItemsControl привязан к коллекции объектов, каждый из которых имеет свойства Left / Top / Width / Height. DataTemplate используется для генерации прямоугольников, которые отображаются в Canvas и расположены правильно (привязка к свойствам Left и Top).
Как я могу реализовать перетаскивание для перемещения этих прямоугольников по холсту?

Фон для моего вопроса:
Мое приложение WP7 отображает «CanvasItemsControl», определенный следующим образом:

public class CanvasItemsControl : ItemsControl
    {
        public string XBindingPath { get; set; }
        public string YBindingPath { get; set; }

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            FrameworkElement contentitem = element as FrameworkElement;
            if (XBindingPath != null && YBindingPath != null)
            {
                Binding xBinding = new Binding(XBindingPath);
                Binding yBinding = new Binding(YBindingPath);
                if (contentitem != null)
                {
                    contentitem.SetBinding(Canvas.LeftProperty, xBinding);
                    contentitem.SetBinding(Canvas.TopProperty, yBinding);
                }
            }
            base.PrepareContainerForItemOverride(element, item);
        }
    }

и используется в XAML следующим образом:

<hh:CanvasItemsControl Grid.Row="1" x:Name="TheItemsControl"
   Style="{StaticResource CanvasItemsControlStyle}"
   ItemsSource="{Binding AllObjects}"
   XBindingPath="Left" YBindingPath="Top" />

Это стиль для CanvasItemsControl:

<Style x:Key="CanvasItemsControlStyle" TargetType="local:CanvasItemsControl">
        <Setter Property="ItemTemplate" Value="{StaticResource ObjectTemplate}"/>
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter> 
</Style>

И это DataTemplate, который я использую для визуализации моего класса:

    <DataTemplate x:Key="ObjectTemplate"  >
        <Border Background="{Binding Brush}" 
                Width="{Binding Width}"
                Height="{Binding Height}">
            <TextBlock Text="{Binding Description}"/>
        </Border>
    </DataTemplate>

Источник CanvasItemsControl - это коллекция объектов, которые имеют свойства Left, Top, Width, Height, Brush и т. Д.

Мой вопрос
Как видите, конечный результат заключается в том, что при добавлении элементов в коллекцию AllObjects каждый объект отображается и правильно размещается на холсте. Теперь мне нужно перетащить / переместить / переместить эти объекты вокруг холста. Какой подход вы бы посоветовали мне использовать для реализации перетаскивания? Можете ли вы провести меня через этот процесс?

Спасибо

1 Ответ

0 голосов
/ 04 февраля 2011

Вот решение моего вопроса (по крайней мере, лучший на мой взгляд):

1) Использование обычного Canvas в отличие от пользовательского элемента управления, унаследованного от Canvas.
2) Использование пользовательского элемента управления, берущего контекст данных (экземпляр моей бизнес-сущности) через конструктор
3) Связывание между свойствами Left / Top моего бизнес-класса и Canvas.Left / Top объявлено на уровне UserControl.
4) Использование пользовательского поведения, унаследованного от System.Windows.Interactivity.Behavior. Это поведение привязано к пользовательскому элементу управления.

Я хотел бы поблагодарить Кельвина Шротенбоера и Джо Гершгорина за огромную помощь.

<!--____ The UserControl ____-->
   <UserControl...      Canvas.Left={Binding Left}" Canvas.Top={Binding Top}">
      <Grid.... layout of the UserControl instead of using a DataTemplate/>
      <i:Interaction.Behaviors>
         <MyExample:MyMouseDragElementBehavior/>
      </i:Interaction.Behaviors>
   </UserControl>

Пользовательское поведение:

public class MyMouseDragElementBehavior : Behavior<FrameworkElement>
{
    public event MouseEventHandler DragBegun;
    public event MouseEventHandler DragFinished;
    public event MouseEventHandler Dragging;

    private Point relativePosition;

    public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled", typeof(bool), typeof(MyMouseDragElementBehavior), new PropertyMetadata(true));

    public bool IsEnabled
    {
        get
        {
            return (bool)GetValue(IsEnabledProperty);
        }
        set
        {
            SetValue(IsEnabledProperty, value);
        }
    }

    protected override void OnAttached()
    {
        AssociatedObject.AddHandler(
            UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonDown), false);
        base.OnAttached();
    }

    protected override void OnDetaching()
    {
        AssociatedObject.RemoveHandler(
            UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnMouseLeftButtonDown));
        base.OnDetaching();
    }

    private static int zIndex = 0;

    private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (!IsEnabled)
        {
            return;
        }
        zIndex++;
        Canvas.SetZIndex(AssociatedObject, zIndex);

        StartDrag(e.GetPosition(AssociatedObject));
        if (DragBegun != null)
        {
            DragBegun(this, e);
        }
    }

    private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        AssociatedObject.ReleaseMouseCapture();
    }

    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        HandleDrag(e.GetPosition(AssociatedObject));
        if (Dragging != null)
        {
            Dragging(this, e);
        }
    }

    internal void HandleDrag(Point newPositionInElementCoordinates)
    {
        double x = newPositionInElementCoordinates.X - relativePosition.X;
        double y = newPositionInElementCoordinates.Y - relativePosition.Y;

        if (AssociatedObject != null)
        {
            var currentLeft = Canvas.GetLeft(AssociatedObject);
            var currentTop = Canvas.GetTop(AssociatedObject);
            Canvas.SetLeft(AssociatedObject, currentLeft + x);
            Canvas.SetTop(AssociatedObject, currentTop + y);
        }
    }

    internal void StartDrag(Point positionInElementCoordinates)
    {
        relativePosition = positionInElementCoordinates;
        AssociatedObject.CaptureMouse();
        AssociatedObject.MouseMove += OnMouseMove;
        AssociatedObject.LostMouseCapture += OnLostMouseCapture;
        AssociatedObject.AddHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(OnMouseLeftButtonUp), false);
    }

    internal void EndDrag()
    {
        AssociatedObject.MouseMove -= OnMouseMove;
        AssociatedObject.LostMouseCapture -= OnLostMouseCapture;
        AssociatedObject.RemoveHandler(
            UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(OnMouseLeftButtonUp));
    }

    private void OnLostMouseCapture(object sender, MouseEventArgs e)
    {
        EndDrag();
        if (DragFinished != null)
        {
            DragFinished(this, e);
        }
    }
}
...