14

ユーザーがフォームを含む UserControl サブクラスを追加できる Canvas があります。ユーザーは、これらの UserControl を Canvas 内でドラッグできる必要があります。

WPF でこれを行うベスト プラクティスは何ですか?

4

7 に答える 7

42

これは、WPFではなくSilverlightで実行されますが、同じように機能するはずです。

コントロールに2つのプライベートプロパティを作成します。

protected bool isDragging;  
private Point clickPosition;

次に、コントロールのコンストラクターでいくつかのイベントハンドラーをアタッチします。

this.MouseLeftButtonDown += new MouseButtonEventHandler(Control_MouseLeftButtonDown);
this.MouseLeftButtonUp += new MouseButtonEventHandler(Control_MouseLeftButtonUp);
this.MouseMove += new MouseEventHandler(Control_MouseMove);

次に、これらのメソッドを作成します。

private void Control_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    isDragging = true;
    var draggableControl = sender as UserControl;
    clickPosition = e.GetPosition(this);
    draggableControl.CaptureMouse();
}

private void Control_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    isDragging = false;
    var draggable = sender as UserControl;
    draggable.ReleaseMouseCapture();
}

private void Control_MouseMove(object sender, MouseEventArgs e)
{
    var draggableControl = sender as UserControl;

    if (isDragging && draggableControl != null)
    {
        Point currentPosition = e.GetPosition(this.Parent as UIElement);

        var transform = draggableControl.RenderTransform as TranslateTransform;
        if (transform == null)
        {
            transform = new TranslateTransform();
            draggableControl.RenderTransform = transform;
        }

        transform.X = currentPosition.X - clickPosition.X;
        transform.Y = currentPosition.Y - clickPosition.Y;
    }
}

ここで注意すべき点がいくつかあり
ます。1。これはキャンバスにある必要はありません。スタックパネルまたはグリッドに配置することもできます。
2.これにより、コントロール全体がドラッグ可能になります。つまり、コントロール内の任意の場所をクリックしてドラッグすると、コントロール全体がドラッグされます。それがまさにあなたが望むものであるかどうかわからない。

編集
-あなたの質問の詳細のいくつかを拡張します:これを実装する最良の方法は、このコードで構築されたDraggableControlと呼ばれるUserControlから継承するクラスを作成することです。その後、すべてのドラッグ可能なコントロールはDraggableControlを拡張する必要があります。

編集2-このコントロールにデータグリッドがある場合、小さな問題があります。データグリッドの列を並べ替えると、MouseLeftButtonUpイベントは発生しません。isDraggingが保護されるようにコードを更新しました。最善の解決策は、この匿名のメソッドをデータグリッドのLostMouseCaptureイベントに関連付けることです。

this.MyDataGrid.LostMouseCapture += (sender, e) => { this.isDragging = false; };
于 2009-09-29T23:42:26.983 に答える
4

誰かが最小限の解決策を試してみたい場合は、ここでMouseMoveイベントを使用します。

レイアウト

<Canvas 
  Background='Beige'
  Name='canvas'>

  <Rectangle 
    Width='50'
    Height='50'
    Fill='LightPink'
    Canvas.Left='350'
    Canvas.Top='175'
    MouseMove='Rectangle_MouseMove' />

</Canvas>

コードビハインド

void OnMouseMove(object sender, MouseEventArgs e)
{
  if (e.Source is Shape shape)
  {
    if (e.LeftButton == MouseButtonState.Pressed)
    {
      Point p = e.GetPosition(canvas);
      Canvas.SetLeft(shape, p.X - shape.ActualWidth / 2);
      Canvas.SetTop(shape, p.Y - shape.ActualHeight / 2);
      shape.CaptureMouse();
    }
    else
    {
      shape.ReleaseMouseCapture();
    }
  }
}
于 2019-10-09T18:23:27.560 に答える
-3

これを WPF と UWP ストア アプリの両方に実装しました。そして、それを使用しているコントロールではなく、ユーザーコントロール自体にすべてのコードを追加しました。必要に応じて変更できます。

WPF

public partial class DragUserControl : UserControl
{
    public DragUserControl()
    {
        InitializeComponent();
    }

    object MovingObject;
    double FirstXPos, FirstYPos;

    private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        this.MovingObject = this;
        FirstXPos = e.GetPosition(MovingObject as Control).X;
        FirstYPos = e.GetPosition(MovingObject as Control).Y;

        Canvas canvas = this.Parent as Canvas;
        if (canvas != null)
        {
            canvas.PreviewMouseMove += this.MouseMove;
        }
    }

    private void MouseMove(object sender, MouseEventArgs e)
    {
        /*
         * In this event, at first we check the mouse left button state. If it is pressed and 
         * event sender object is similar with our moving object, we can move our control with
         * some effects.
         */
        Canvas canvas = sender as Canvas;

        Point canvasPoint = e.GetPosition(canvas);
        Point objPosition = e.GetPosition((MovingObject as FrameworkElement));
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            if (MovingObject != null)
            {
//This condition will take care that control should not go outside the canvas.
                    if ((e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos > 0) && (e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos < canvas.ActualWidth - (MovingObject as FrameworkElement).ActualWidth))
                    {
                        (MovingObject as FrameworkElement).SetValue(Canvas.LeftProperty, e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).X - FirstXPos);
                    }

//This condition will take care that control should not go outside the canvas.
                    if ((e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos > 0) && (e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos < canvas.ActualHeight - (MovingObject as FrameworkElement).ActualHeight))
                    {
                        (MovingObject as FrameworkElement).SetValue(Canvas.TopProperty, e.GetPosition((MovingObject as FrameworkElement).Parent as FrameworkElement).Y - FirstYPos);
                    }
                }
            }
        }

        private void Ellipse_PreviewMouseLeftButtonUp_1(object sender, MouseButtonEventArgs e)
        {
            MovingObject = null;
        }
    }

Button_MouseLeftButtonDown は、コントロールをドラッグするボタンのクリック イベントです。

UWP

 public sealed partial class DragUserControl : UserControl
    {
        MovingObject;
        double FirstXPos, FirstYPos;

        public DragUserControl()
        {
            InitializeComponent();
        }

       private void Ellipse_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            this.MovingObject = this;

            FirstXPos = e.GetCurrentPoint(MovingObject as Control).Position.X;
            FirstYPos = e.GetCurrentPoint(MovingObject as Control).Position.Y;

            Canvas canvas = this.Parent as Canvas;
            if (canvas != null)
            {
                canvas.PointerMoved += Canvas_PointerMoved;
            }
        }

        private void Canvas_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            if (MovingObject != null)
            {
                Canvas canvas = sender as Canvas;

                Point canvasPoint = e.GetCurrentPoint(canvas).Position;
                Point objPosition = e.GetCurrentPoint((MovingObject as FrameworkElement)).Position;
                if (e.GetCurrentPoint(MovingObject as Control).Properties.IsLeftButtonPressed) //e.Pointer.IsInContact ==true)
                {
//This condition will take care that control should not go outside the canvas
                    if ((e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.X - FirstXPos > 0) && (e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.X - FirstXPos < canvas.ActualWidth - (MovingObject as FrameworkElement).ActualWidth))
                    {
                        (MovingObject as FrameworkElement).SetValue(Canvas.LeftProperty, e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.X - FirstXPos);
                    }

//This condition will take care that control should not go outside the canvas
                    if ((e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.Y - FirstYPos > 0) && (e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.Y - FirstYPos < canvas.ActualHeight - (MovingObject as FrameworkElement).ActualHeight))
                    {
                        (MovingObject as FrameworkElement).SetValue(Canvas.TopProperty, e.GetCurrentPoint((MovingObject as FrameworkElement).Parent as FrameworkElement).Position.Y - FirstYPos);
                    }
                }
            }
        }

        private void Ellipse_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            MovingObject = null;
        }
}

Ellipse_PointerPressed は、コントロールをドラッグする楕円のクリック イベントです。

于 2016-10-05T04:54:28.673 に答える