WP7 - 拖放从 Canvas 内的 DataTemplate 创建的对象

发布于 2024-10-14 22:26:23 字数 2550 浏览 6 评论 0原文

概览:
我的应用程序显示一个 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 的源是对象的集合,具有左侧、顶部、宽度、高度、画笔等属性。

我的问题
正如您所看到的,最终结果是,当您将项目添加到 AllObjects 集合时,每个对象都会在画布中正确渲染和定位。现在我需要在画布上拖/放/移动这些对象。您建议我使用什么方法来实现拖/放?您能指导我完成整个过程吗?

谢谢

At a glance:
My app displays an ItemsControl containing a Canvas as its ItemsPanel. The ItemsControl is bound to a collection of objects, each having Left/Top/Width/Height properties. A DataTemplate is used to generate rectangles that are rendered in the Canvas and positioned correctly (binding on the Left and Top properties).
How can I implement drag/drop to move these rectangles around the Canvas?

Background for my question:
My WP7 app displays a "CanvasItemsControl" defined as follows:

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);
        }
    }

and used in XAML as follows:

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

This is the style for the 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>

And this is the DataTemplate I use to render my class:

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

The source of the CanvasItemsControl is a collection of objects that have the properties Left, Top, Width, Height, Brush, etc.

My question
As you can see, the end result is, as you add items to the AllObjects collection, each object gets rendered and positioned correctly in the canvas. Now I need to drag/drop/move these objects around the canvas. What approach would you advise me to use to implement drag/drop? Can you please guide me through the process?

Thank you

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

予囚 2024-10-21 22:26:23

这是我的问题的解决方案(至少在我看来是最好的解决方案):

1)使用常规 Canvas,而不是从 Canvas 继承的自定义控件。
2)使用用户控件通过构造函数获取数据上下文(我的业务实体的实例)
3) 我的业务类的 Left/Top 属性和 Canvas.Left/Top 之间的绑定是在 UserControl 级别声明的。
4) 使用继承自System.Windows.Interactivity.Behavior的自定义行为。此行为附加到用户控件。

我要感谢 Calvin Schrotenboer 和 Joe Gershgorin 的巨大贡献帮助。

<!--____ 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);
        }
    }
}

Here's the solution to my question (at least the best one in my opinion):

1) Use of a regular Canvas as opposed of a custom control inherited from Canvas.
2) Use of a user control taking the data context (the instance of my business entity) via constructor
3) The binding between the Left/Top properties of my business class and the Canvas.Left/Top is declared at the UserControl level.
4) Use of a custom behavior inheriting from System.Windows.Interactivity.Behavior. This behavior is attached to the User Control.

I would like to acknowlege Calvin Schrotenboer and Joe Gershgorin for their immense help.

<!--____ 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>

The custom behavior:

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);
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文