C# 拖动 WPF 弹出控件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/222029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Drag WPF Popup control
提问by Joachim Kerschbaumer
the WPF Popup control is nice, but somewhat limited in my opinion. is there a way to "drag" a popup around when it is opened (like with the DragMove() method of windows)?
WPF Popup 控件很好,但在我看来有些有限。有没有办法在打开时“拖动”弹出窗口(例如使用窗口的 DragMove() 方法)?
can this be done without big problems or do i have to write a substitute for the popup class myself? thanks
这可以在没有大问题的情况下完成还是我必须自己编写弹出类的替代品?谢谢
采纳答案by jacob
Here's a simple solution using a Thumb.
这是一个使用 Thumb 的简单解决方案。
- Subclass Popup in XAML and codebehind
- Add a Thumb with width/height set to 0 (this could also be done in XAML)
- Listen for MouseDown events on the Popup and raise the same event on the Thumb
- Move popup on DragDelta
- XAML 和代码隐藏中的子类弹出窗口
- 添加宽度/高度设置为 0 的 Thumb(这也可以在 XAML 中完成)
- 在 Popup 上侦听 MouseDown 事件并在 Thumb 上引发相同的事件
- 在 DragDelta 上移动弹出窗口
XAML:
XAML:
<Popup x:Class="PopupTest.DraggablePopup" ...>
<Canvas x:Name="ContentCanvas">
</Canvas>
</Popup>
C#:
C#:
public partial class DraggablePopup : Popup
{
public DraggablePopup()
{
var thumb = new Thumb
{
Width = 0,
Height = 0,
};
ContentCanvas.Children.Add(thumb);
MouseDown += (sender, e) =>
{
thumb.RaiseEvent(e);
};
thumb.DragDelta += (sender, e) =>
{
HorizontalOffset += e.HorizontalChange;
VerticalOffset += e.VerticalChange;
};
}
}
回答by Jobi Joy
There is no DragMove for PopUp. Just a small work around, there is lot of improvements you can add to this.
PopUp 没有 DragMove。只是一个小小的工作,你可以添加很多改进。
<Popup x:Name="pop" IsOpen="True" Height="200" Placement="AbsolutePoint" Width="200">
<Rectangle Stretch="Fill" Fill="Red"/>
</Popup>
In the code behind , add this mousemove event
在后面的代码中,添加这个 mousemove 事件
pop.MouseMove += new MouseEventHandler(pop_MouseMove);
void pop_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
pop.PlacementRectangle = new Rect(new Point(e.GetPosition(this).X,
e.GetPosition(this).Y),new Point(200,200));
}
}
回答by user722886
Private Point startPoint;
private void Window_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(null);
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Point relative = e.GetPosition(null);
Point AbsolutePos = new Point(relative.X + this.Left, relative.Y + this.Top);
this.Top = AbsolutePos.Y - startPoint.Y;
this.Left = AbsolutePos.X - startPoint.X;
}
}
This works for dragging my window, but like it was told if i move the mouse to fast, it would get out of window and stop raising the event. Without mentioning the dragging is not smooth at all. Does anyone knows how to do it properly, nice and smooth dragging, without loosing it when dragged too fast??? Post a simple example if possible, other than a whole tutorial that would get beginners like me lost in code. Thanks!
这适用于拖动我的窗口,但就像有人告诉我如果我快速移动鼠标,它会离开窗口并停止引发事件。更不用说拖动根本不顺畅。有谁知道如何正确地进行拖动,漂亮而平滑的拖动,拖动太快时不会丢失它???如果可能的话,发布一个简单的例子,而不是一个会让像我这样的初学者迷失在代码中的整个教程。谢谢!
回答by Ashley Davis
Another way of achieving this is to set your Popup's placement to MousePoint. This makes the popup initially appear at the position of the mouse cursor.
实现此目的的另一种方法是将 Popup 的位置设置为 MousePoint。这使得弹出窗口最初出现在鼠标光标的位置。
Then you can either use a Thumb or MouseMove event to set the Popup's HorizontalOffset & VerticalOffset. These properties shift the Popup away from its original position as the user drags it.
然后您可以使用 Thumb 或 MouseMove 事件来设置 Popup 的 HorizontalOffset 和 VerticalOffset。当用户拖动它时,这些属性将 Popup 从其原始位置移开。
Remember to reset HorizontalOffset and VerticalOffset back to zero for the next use of the popup!
请记住将 HorizontalOffset 和 VerticalOffset 重置为零,以便下次使用弹出窗口!
回答by Leon
The issue with loosing the mouse when moving too fast, could be resolved
移动太快时失去鼠标的问题,可以解决
This is taken from msdn:
这是从 msdn 中获取的:
The new window contains the Child content of Popup.
The Popup control maintains a reference to its Child content as a logical child. When the new window is created, the content of Popup becomes a visual child of the window and remains the logical child of Popup. Conversely, Popup remains the logical parent of its Child content.
新窗口包含 Popup 的 Child 内容。
Popup 控件维护对其子内容的引用作为逻辑子项。创建新窗口时,Popup 的内容成为窗口的可视子窗口,并保持为 Popup 的逻辑子窗口。相反,Popup 仍然是其子内容的逻辑父级。
In the other words, the child of the popup is displayed in standalone window.
换句话说,弹出窗口的子窗口显示在独立窗口中。
So when trying to the following:Popup.CaptureMouse()
is capturing the wrapper window and not the popup itself. Instead using Popup.Child.CaptureMouse()
captures the actual popup.
因此,当尝试执行以下操作时:Popup.CaptureMouse()
正在捕获包装器窗口而不是弹出窗口本身。而是使用Popup.Child.CaptureMouse()
捕获实际的弹出窗口。
And all other events should be registered using Popup.Child
.
并且所有其他事件都应该使用Popup.Child
.
Like Popup.Child.MouseMove
, Popup.Child.LostCapture
and so on
像Popup.Child.MouseMove
,Popup.Child.LostCapture
等等
This has been tested and works perfectly fine
这已经过测试并且运行良好
回答by Gregory A. Owen
Building off of Jobi Joy's answer, I found a re-useable solution that allows you to add as a control within xaml of an existing control/page. Which was not possible adding as Xaml with a Name since it has a different scope.
基于Jobi Joy的回答,我找到了一个可重复使用的解决方案,它允许您在现有控件/页面的 xaml 中作为控件添加。由于 Xaml 具有不同的范围,因此无法将其添加为带有名称的 Xaml。
[ContentProperty("Child")]
[DefaultEvent("Opened")]
[DefaultProperty("Child")]
[Localizability(LocalizationCategory.None)]
public class DraggablePopup : Popup
{
public DraggablePopup()
{
MouseDown += (sender, e) =>
{
Thumb.RaiseEvent(e);
};
Thumb.DragDelta += (sender, e) =>
{
HorizontalOffset += e.HorizontalChange;
VerticalOffset += e.VerticalChange;
};
}
/// <summary>
/// The original child added via Xaml
/// </summary>
public UIElement TrueChild { get; private set; }
public Thumb Thumb { get; private set; } = new Thumb
{
Width = 0,
Height = 0,
};
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
TrueChild = Child;
var surrogateChild = new StackPanel();
RemoveLogicalChild(TrueChild);
surrogateChild.Children.Add(Thumb);
surrogateChild.Children.Add(TrueChild);
AddLogicalChild(surrogateChild);
Child = surrogateChild;
}
}