我正在使用带有WPF的C#。我有一个按钮网格,我需要执行以下操作:如果用户按下一个按钮,移动光标并在另一个按钮上释放它,第一个按钮的内容将移动到另一个按钮,类似于拖动。
我尝试使用previewmousedown和previewmouseup按钮事件来了解按下鼠标的按钮以及释放它的按钮,但是按下鼠标的按钮也触发了previewmouseup事件(而不是按下鼠标的按钮)鼠标被释放)。
有关如何以其他方式实现此问题的任何想法,好吗?非常感谢。
答案 0 :(得分:1)
最简单的拖拉方式drop是内置的DragDrop
API。以下是您的概念验证,通常可以点击按钮 *和* 来交换其内容。
如果您想更改行为以便复制或移动内容(而不是交换),只需更改OnButtonDrop
中评论下的行。
<强> ButtonDragging.xaml:强>
<Window x:Class="WpfTest2.ButtonDragging"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel LastChildFill="True">
<Label x:Name="_statusLabel" DockPanel.Dock="Bottom" Content=" " />
<Grid x:Name="_grid" />
</DockPanel>
</Window>
<强> ButtonDragging.xaml.cs:强>
public partial class ButtonDragging
{
private Button _mouseDownButton;
private Point _mouseDownLocation;
public ButtonDragging()
{
InitializeComponent();
BuildButtonGrid();
}
private void BuildButtonGrid()
{
const int rows = 5;
const int columns = 5;
var starLength = new GridLength(1d, GridUnitType.Star);
for (var i = 0; i < rows; i++)
_grid.RowDefinitions.Add(new RowDefinition { Height = starLength });
for (var i = 0; i < columns; i++)
_grid.ColumnDefinitions.Add(new ColumnDefinition { Width = starLength });
for (var i = 0; i < rows; i++)
{
for (var j = 0; j < columns; j++)
{
var button = new Button { Content = $@"({i}, {j})", AllowDrop = true };
Grid.SetColumn(button, i);
Grid.SetRow(button, j);
button.PreviewMouseMove += OnButtonMouseMove;
button.PreviewMouseLeftButtonDown += OnButtonLeftButtonDown;
button.PreviewMouseLeftButtonUp += OnButtonLeftButtonUp;
button.Drop += OnButtonDrop;
button.Click += OnButtonClick;
button.LostMouseCapture += OnButtonLostMouseCapture;
_grid.Children.Add(button);
}
}
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
_statusLabel.Content = $@"You clicked {(sender as Button)?.Content}!";
}
private void ClearPendingDrag()
{
_mouseDownButton = null;
_mouseDownLocation = default(Point);
}
private void OnButtonDrop(object sender, DragEventArgs e)
{
ClearPendingDrag();
var source = e.Data.GetData(typeof(object)) as Button;
if (source == null)
return;
var target = (Button)sender;
if (target == source)
return;
var sourceContent = source.Content;
var targetContent = target.Content;
// As a proof of concept, this swaps the content of the source and target.
// Change as necessary to get the behavior you want.
target.Content = sourceContent;
source.Content = targetContent;
_statusLabel.Content = $@"You swapped {sourceContent} with {targetContent}!";
}
private void OnButtonLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var button = (Button)sender;
_mouseDownButton = button;
_mouseDownLocation = e.GetPosition(button);
if (!Mouse.Capture(button, CaptureMode.SubTree))
ClearPendingDrag();
}
private void OnButtonLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ClearPendingDrag();
}
private void OnButtonMouseMove(object sender, MouseEventArgs e)
{
if (_mouseDownButton == null)
return;
var position = e.GetPosition(_mouseDownButton);
var distance = position - _mouseDownLocation;
if (Math.Abs(distance.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(distance.Y) > SystemParameters.MinimumVerticalDragDistance)
{
var button = (Button)sender;
var data = new DataObject(typeof(object), button);
data.SetData("Source", sender);
DragDrop.DoDragDrop(button, data, DragDropEffects.Move);
ClearPendingDrag();
}
}
private void OnButtonLostMouseCapture(object sender, MouseEventArgs e)
{
ClearPendingDrag();
}
}
请注意,可能存在一些对MVVM更友好的第三方(和开源)拖放解决方案。这值得一试,但这应该可以为您提供最低限度的可交付成果。
答案 1 :(得分:-1)
看一下这篇博客文章。这是我在线阅读的最好的拖放文章。
以下链接是拖放操作的一系列事件:
通过调用源代码管理的DoDragDrop
方法启动拖动。
DoDragDrop
方法有两个参数:
data
,指定要传递的数据
allowedEffects
,指定允许哪些操作(复制和/或移动)
将自动创建一个新的DataObject
对象。
这又会引发GiveFeedback
事件。在大多数情况下,您不必担心GiveFeedback
事件,但如果您想在拖动过程中显示自定义鼠标指针,则可以在此处添加代码。
将AllowDrop
属性设置为True
的任何控件都是潜在的丢弃目标。 AllowDrop
属性可以在设计时在“属性”窗口中设置,也可以在Form_Load
事件中以编程方式设置。
当鼠标经过每个控件时,会引发该控件的DragEnter
事件。 GetDataPresent
方法用于确保数据格式适合目标控件,Effect属性用于显示相应的鼠标指针。
如果用户在有效的放置目标上释放鼠标按钮,则会引发DragDrop
事件。 DragDrop
事件处理程序中的代码从DataObject
对象中提取数据并将其显示在目标控件中。
要检测源上的鼠标拖动操作,源代码管理需要订阅MouseLeftButtonDown
和MouseMove
。
void Window1_Loaded(object sender, RoutedEventArgs e)
{
this.DragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
this.DragSource.PreviewMouseMove += new MouseEventHandler(DragSource_PreviewMouseMove);
}
防止开始误拖&amp;如果用户意外拖动操作,您可以使用SystemParameters.MinimumHorizontalDragDistance
和SystemParameters.MinimumVerticalDragDistance
。
void DragSource_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && !IsDragging)
{
Point position = e.GetPosition(null);
if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
{
StartDrag(e);
}
}
}
void DragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_startPoint = e.GetPosition(null);
}
现在你检测到一个拖动操作,你需要知道的只是落入。
可以像这样做一个没有任何影响的简单场景。
private void StartDrag(MouseEventArgs e)
{
IsDragging = true;
DataObject data = new DataObject(System.Windows.DataFormats.Text.ToString(), "abcd");
DragDropEffects de = DragDrop.DoDragDrop(this.DragSource, data, DragDropEffects.Move);
IsDragging = false;
}
我认为这可以帮助你入门。我真的建议你阅读链接中的完整帖子。
https://blogs.msdn.microsoft.com/jaimer/2007/07/12/drag-amp-drop-in-wpf-explained-end-to-end/