我正在尝试制作一个在画布上拖动的UserControl。我正在使用C#和WPF。我在网上看到了很多例子,但我只需要最低限度的内容。
我找到了一篇文章:“ WPF中的可拖动控件”
如果您想手动操作,请使用以下算法:
在发生MouseDown事件时:保存鼠标位置,控件的TopLeft位置以及这些坐标的delta(offset),并设置一些布尔字段标志,例如。 IsDragStartted为true。 在MouseMove上,检查拖动是否开始,并使用“鼠标位置和偏移量”来计算控件的TopLeft位置的新值
在MouseUp事件上,将IsDragStarted设置为false
我在应用此程序时遇到麻烦。
公共局部类UserControl1:UserControl {
private Point startingMousePosition;
private Point endingMousePosition;
private Point startingControlPosition;
bool isDragStarted;
public UserControl1()
{
InitializeComponent();
}
private void Grid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if(!isDragStarted)
{
startingControlPosition.X = Canvas.GetLeft(this);
startingControlPosition.Y = Canvas.GetTop(this);
startingMousePosition.X = e.GetPosition(this.Parent as Canvas).X;
startingMousePosition.Y = e.GetPosition(this.Parent as Canvas).Y;
}
}
private void Grid_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
isDragStarted = true;
if (isDragStarted)
{
endingMousePosition.X = e.GetPosition(this.Parent as Canvas).X;
endingMousePosition.Y = e.GetPosition(this.Parent as Canvas).Y;
Canvas.SetLeft(this, endingMousePosition.X - startingControlPosition.X);
Canvas.SetTop(this, endingMousePosition.Y - startingControlPosition.Y);
}
}
}
private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
isDragStarted = false;
}
}
这是我的主窗口WPF表单的代码:
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
UserControl1 userCTL;
public MainWindow()
{
InitializeComponent();
userCTL = new UserControl1();
userCTL.Width = 50;
userCTL.Height = 100;
Canvas.SetTop(userCTL,20);
Canvas.SetLeft(userCTL, 20);
CanvasMain.Children.Add(userCTL);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(userCTL);
if (myAdornerLayer != null)
{
myAdornerLayer.Add(new SimpleCircleAdorner(userCTL));
}
}
}
}
这是我在主窗口中的WPF代码:
<Window x:Class="WpfApplicationEvent.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="374.306" Width="594.271" Loaded="Window_Loaded">
<Grid>
<ScrollViewer Margin="46,23,74,33" PanningMode="Both" HorizontalScrollBarVisibility="Visible">
<Canvas x:Name="CanvasMain" Height="395" Width="506">
</Canvas>
</ScrollViewer>
</Grid>
</Window>
我还尝试放置装饰物,以便最终调整控件的大小。装饰没有了,但是他们什么也没做。
我在创建的UserControl1中拥有所有拖动控件,然后将其拖动,但是当我再次单击UserControl1实例再次拖动它时,它将重置为SetTop(0)和SetLeft(0)位置。它怪异地跳到那里!我期望将UserControl1实例拖到光标所在的位置。会在第一次尝试时执行它,但是随后我单击UserControl1再次将其拖动一次,它会跳到(0,0)或接近它。
答案 0 :(得分:0)
您在这里遇到了一些问题...
因此您的画布XAML现在应如下所示:
<Canvas x:Name="CanvasMain" Height="395" Width="506"
PreviewMouseMove="CanvasMain_PreviewMouseMove"
PreviewMouseUp="CanvasMain_PreviewMouseUp" />
您的后台代码应如下所示:
public MainWindow()
{
InitializeComponent();
var userCTL = new UserControl(); // <-- replace with your own control
userCTL.Background = Brushes.Blue; // <-- added this so I can see it
userCTL.Width = 50;
userCTL.Height = 100;
Canvas.SetTop(userCTL, 20);
Canvas.SetLeft(userCTL, 20);
userCTL.PreviewMouseDown += UserCTL_PreviewMouseDown;
CanvasMain.Children.Add(userCTL);
}
UIElement dragObject = null;
Point offset;
private void UserCTL_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
this.dragObject = sender as UIElement;
this.offset = e.GetPosition(this.CanvasMain);
this.offset.Y -= Canvas.GetTop(this.dragObject);
this.offset.X -= Canvas.GetLeft(this.dragObject);
this.CanvasMain.CaptureMouse();
}
private void CanvasMain_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (this.dragObject == null)
return;
var position = e.GetPosition(sender as IInputElement);
Canvas.SetTop(this.dragObject, position.Y - this.offset.Y);
Canvas.SetLeft(this.dragObject, position.X - this.offset.X);
}
private void CanvasMain_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
this.dragObject = null;
this.CanvasMain.ReleaseMouseCapture();
}
您可能还希望向“画布”添加MouseLeave处理程序,以阻止用户将控件拖到可见客户区域之外。