我正在尝试制作一个拖动画布的UserControl。我正在使用C#和WPF。我在网上看到很多例子,但我只需要最低限度。
我发现了一篇文章:“WPF中的可拖动控件”
如果您想手动使用以下算法:
在MouseDown事件中:保存鼠标位置,TopLeft控制位置和这些坐标的delta(偏移),并设置一些布尔字段标志,例如。 IsDragStartted为true。在MouseMove上检查拖动是否已启动并使用鼠标位置和偏移量来计算TopLeft控件位置的新值
在MouseUp事件上将IsDragStarted设置为false
我无法应用此功能。
public partial class 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)或接近它。
你在这里遇到了几个问题......
所以你的画布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();
}
您可能还希望向Canvas添加MouseLeave处理程序以停止用户在可见客户区域外拖动控件。