更新:我发现,如果我总是从 MapCanvas 中的 OnMouseLeftButtonDown 返回,我就能按照我想要的方式使用弹出窗口。这向我表明 MapCanvas 的行为正在阻止罪魁祸首。我的问题可能很快就会有答案。
我担心导致这个问题的最终问题还没有解决,所以我会尽可能多地记录我的工作。对于这篇很长的帖子,我深表歉意,但我想尽可能清楚地分享我所拥有的。下面是我面临的问题的摘要:
我有一个由 map 线包含的弹出窗口,它本身包含在 map 中。当用户左键单击并拖动时,它会拖动 map 。我写了一个行为也可以单击并拖动弹出窗口。当我左键单击弹出窗口并尝试拖动它时,我改为拖动 map - 弹出窗口保持静止。当我松开鼠标左键时,弹出窗口就会“粘”在我的光标上,它会拖到我移动鼠标的任何地方。
好了,现在开始详细介绍:
我编写了一个在 WPF 应用程序中使用的自定义映射控件。我无法分享整个定义,但一些重要的部分如下所示:
public class MapCanvas : Canvas
{
public override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (e.ClickCount >= 2)
{
//We zoom in a level
}
else
{
this.Focus(); //We get the keyboard
if (this.CaptureMouse())
{
mouseCaptured = true;
previousMouse = e.GetPosition(null);
}
}
}
public override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
this.ReleaseMouseCapture();
mouseCaptured = false;
}
public override void OnMouseMove(MouseButtonEventArgs e)
{
base.OnMouseMove(e);
if (mouseCaptured)
{
//Translate the map tiles based on the current position of the mouse
}
}
}
我共享覆盖,因为它们是我处理 map 交互(例如拖动 map 、双击缩放等)的方式。我还认为它在导致问题的原因中发挥了作用。
我还编写了一个名为 MapLine 的类型,它绑定(bind)到一组地理空间坐标,将它们转换为屏幕点,并将它们显示在 map 上。这些行被添加到我的 MapCanvas 中的 VisualCollection。我已经修剪了它们的定义并将其布置在下面:
public abstract class MapLine : FrameworkElement
{
private VisualCollection popupChildren;
private VisualCollection regularChildren;
protected override int VisualChildrenCount
{
get
{
return regularChildren.Count;
}
}
protected override Visual GetVisualChild(int index)
{
if (index < 0 || index >= VisualChildrenCount)
throw new ArgumentOutOfRangeException("index");
else
{
return regularChildren[index];
}
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
HitTestResult result = VisualTreeHelper.HitTest(this, Mouse.GetPosition(this));
if (result != null && result.VisualHit is DrawingVisual)
{
//If we find the Visual in our collection of regular children, we launch a new popup
if(ThisIsRegularChild((DrawingVisual)result.VisualHit))
{
Popup pointPopup = GeneratePopup();
this.popupChildren.Add(pointPopup);
pointPopup.IsOpen = true;
}
}
base.OnMouseLeftButtonDown(e);
}
private static Popup GeneratePopup()
{
Popup popup = new Popup();
Stream popupContentStream = currentAssembly.GetManifestResourceStream("ResourcePath.xaml");
popup.Child = (UIElement)XamlReader.Load(popupContentStream);
popup.StaysOpen = true;
popup.Placement = PlacementMode.Mouse;
popup.AllowsTransparency = true;
Interaction.GetBehaviors(popup).Add(new PopupDragManager());
return popup;
}
}
好吧,总结一下我分享的有关 MapLine 的内容:它还覆盖 OnMouseLeftButtonDown,并检查用户是否单击了此 MapLine 拥有的可视元素;如果我们这样做,我们会启动一个弹出窗口。该 Popup 附加了一个 System.Windows.Interactivity.Behavior - 这似乎是满足我使 popop 可拖动的需求的最简单方法。这是行为的定义:
private class PopupDragManager : Behavior<Popup>
{
private bool mouseDown;
private Point oldMousePosition;
protected override void OnAttached()
{
AssociatedObject.MouseLeftButtonUp += MouseLeftButtonUp;
AssociatedObject.MouseLeftButtonDown += MouseLeftButtonDown;
AssociatedObject.MouseMove += MouseMove;
}
private void MouseLeftButtonDown(object sender, MouseEventArgs e)
{
mouseDown = true;
oldMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
AssociatedObject.Child.CaptureMouse();
}
private void MouseMove(object sender, MouseEventArgs e)
{
if (!mouseDown) return;
var newMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
var offset = newMousePosition - oldMousePosition;
oldMousePosition = newMousePosition;
AssociatedObject.HorizontalOffset += offset.X;
AssociatedObject.VerticalOffset += offset.Y;
}
private void MouseLeftButtonUp(object sender, MouseEventArgs e)
{
mouseDown = false;
AssociatedObject.Child.ReleaseMouseCapture();
}
}
就像 MapCanvas 一样,如果我们按下鼠标左键,移动鼠标,然后释放鼠标左键,我们希望弹出窗口在屏幕上拖动。相反,当我尝试左键单击并拖动时,MapCanvas 会被拖动,如下所示:
在这里,我正在看 map ;单击蓝点可打开弹出窗口。
我刚刚打开我的流行音乐,准备把它拖到一边
您可以看到,减去裁剪引起的抖动,我的弹出窗口保留在原位,而我的 map 已被拖动
在我的屏幕截图中没有显示的是一旦我松开鼠标左键弹出窗口的“粘性”行为:此时弹出窗口将开始拖动,我只能通过双击。
如果你已经做到了这一步,我祝贺你。我只能希望如此大的耐心可能与对我的问题的理解相吻合,并且您可能能够阐明这个错误。
最佳答案
嗯...我今天学到了一些东西。我不知道,在路由事件(可能还有其他事件)中,您可以通过将 EventArgs.Handled 设置为 true 来将事件标记为已处理。
下面的代码解决了我所有的问题:
private void MouseLeftButtonDown(object sender, MouseEventArgs e)
{
mouseDown = true;
oldMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
AssociatedObject.Child.CaptureMouse();
e.Handled = true;
}
这一行简单的新代码可以防止其他任何人获得 MouseLeftButtonDown 事件。
关于c# - 我的可拖动弹出窗口也会拖动拥有它们的视觉元素。我怎样才能解决这个问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26766168/