ユーザーがフォームを含む UserControl サブクラスを追加できる Canvas があります。ユーザーは、これらの UserControl を Canvas 内でドラッグできる必要があります。
WPF でこれを行うベスト プラクティスは何ですか?
ユーザーがフォームを含む UserControl サブクラスを追加できる Canvas があります。ユーザーは、これらの UserControl を Canvas 内でドラッグできる必要があります。
WPF でこれを行うベスト プラクティスは何ですか?
これは、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; };
誰かが最小限の解決策を試してみたい場合は、ここで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();
}
}
}
これを 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 は、コントロールをドラッグする楕円のクリック イベントです。