【问题标题】:WP7 - drag/drop of objects created from a DataTemplate within CanvasWP7 - 拖放从 Canvas 中的 DataTemplate 创建的对象
【发布时间】:2011-01-31 21:04:51
【问题描述】:

一目了然:
我的应用程序显示一个 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 集合时,每个对象都会在画布中正确呈现和定位。现在我需要在画布周围拖放/移动这些对象。你会建议我用什么方法来实现拖放?你能指导我完成整个过程吗?

谢谢

【问题讨论】:

    标签: silverlight windows-phone-7 drag-and-drop datatemplate


    【解决方案1】:

    这是我的问题的解决方案(至少是我认为最好的):

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

    【讨论】:

    • 当然,如果您有更好的解决方案,请告诉我,我会更改接受的答案。
    猜你喜欢
    • 1970-01-01
    • 2014-09-15
    • 2013-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多