C# 我的可拖动弹出窗口也会拖动拥有它们的视觉元素。我怎样才能解决这个问题?
更新:我发现,如果我总是从地图画布中的OnMouseLeftButtonDown返回,我就能够按照我想要的方式使用弹出窗口。这向我表明,MapCanvas的行为正在阻止罪犯。我可能很快就能找到问题的答案 我担心导致这个问题的最终问题一直没有解决,所以我将尽可能多地记录我的工作。很抱歉这是一篇很长的帖子,但我想尽可能清楚地分享我所拥有的。下面是我面临的问题的摘要: 我有一个由地图线包含的弹出窗口,它本身包含在地图中。当用户左键单击并拖动时,它将拖动地图。我写了一个行为来点击并拖动弹出窗口。当我左键单击弹出窗口并尝试拖动它时,我会拖动地图-弹出窗口保持静止。当我松开鼠标左键时,弹出窗口就会“卡”在我的光标上,它会拖到我移动鼠标的任何地方 好了,现在我们来详细介绍一下: 我已经编写了一个用于WPF应用程序的自定义映射控件。我不能分享整个定义,但一些重要的部分如下:C# 我的可拖动弹出窗口也会拖动拥有它们的视觉元素。我怎样才能解决这个问题?,c#,wpf,C#,Wpf,更新:我发现,如果我总是从地图画布中的OnMouseLeftButtonDown返回,我就能够按照我想要的方式使用弹出窗口。这向我表明,MapCanvas的行为正在阻止罪犯。我可能很快就能找到问题的答案 我担心导致这个问题的最终问题一直没有解决,所以我将尽可能多地记录我的工作。很抱歉这是一篇很长的帖子,但我想尽可能清楚地分享我所拥有的。下面是我面临的问题的摘要: 我有一个由地图线包含的弹出窗口,它本身包含在地图中。当用户左键单击并拖动时,它将拖动地图。我写了一个行为来点击并拖动弹出窗口。当我左键
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
}
}
}
我共享覆盖,因为它们是我处理地图交互的方式,如拖动地图、双击缩放等。我还认为它在导致问题的原因中起着作用
我还编写了一个名为MapLine的类型,它绑定到地理空间坐标集合,将它们转换为屏幕点,并在地图上显示它们。这些行将添加到我的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;
}
}
公共抽象类映射行:FrameworkElement
{
儿童专用视觉采集弹出窗口;
儿童的私人视觉采集调节器;
受保护的重写int VisualChildrenCount
{
得到
{
返回正规儿童。计数;
}
}
受保护的重写Visual GetVisualChild(int索引)
{
如果(索引<0 | |索引>=可视儿童计数)
抛出新ArgumentOutOfRangeException(“索引”);
其他的
{
返回正规儿童[索引];
}
}
MouseLeftButtonDown上的受保护覆盖无效(MouseButtonEventArgs e)
{
HitTestResult=VisualTreeHelper.HitTest(this,Mouse.GetPosition(this));
if(result!=null&&result.VisualHit为DrawingVisual)
{
//如果我们在常规儿童的集合中找到了视觉效果,我们将启动一个新的弹出窗口
if(这是RegularChild((DrawingVisual)result.VisualHit))
{
Popup pointPopup=GeneratePopup();
this.popupChildren.Add(pointPopup);
pointPopup.IsOpen=true;
}
}
在MouseLeftButtonDown(e)上的基础上;
}
专用静态弹出窗口GeneratePopup()
{
Popup Popup=新的Popup();
Stream popupContentStream=currentAssembly.GetManifestResourceStream(“ResourcePath.xaml”);
popup.Child=(UIElement)XamlReader.Load(popupContentStream);
popup.StaysOpen=true;
popup.Placement=PlacementMode.Mouse;
popup.allowsttransparency=true;
Interaction.GetBehaviors(popup.Add)(新的PopupDragManager());
返回弹出窗口;
}
}
好的,总结一下我分享的关于地图线的内容:它还覆盖OnMouseLeftButtonDown,并检查用户是否单击了该地图线拥有的视觉元素;如果我们这样做,我们将启动一个弹出窗口。该弹出窗口附带了System.Windows.Interactivity.Behavior,这似乎是满足我的需要的最简单的方法,可以拖动弹出窗口。以下是该行为的定义:
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();
}
}
私有类PopupDragManager:行为
{
私人布尔·穆斯敦;
私密点鼠标定位;
受保护的覆盖无效附加()
{
AssociatedObject.MouseLeftButtonUp+=MouseLeftButtonUp;
AssociatedObject.MouseLeftButtonDown+=MouseLeftButtonDown;
AssociatedObject.MouseMove+=MouseMove;
}
私有void MouseLeftButtonDown(对象发送器,MouseEventArgs e)
{
mouseDown=true;
oldMousePosition=AssociatedObject.PointToScreen(例如GetPosition(AssociatedObject));
AssociatedObject.Child.CaptureMouse();
}
私有void MouseMove(对象发送方,MouseEventArgs e)
{
如果(!mouseDown)返回;
var newMousePosition=AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
var偏移=新鼠标位置-旧鼠标位置;
oldMousePosition=newMousePosition;
AssociatedObject.HorizontalOffset+=offset.X;
AssociatedObject.VerticalOffset+=offset.Y;
}
私有void MouseLeftButtonUp(对象发送器,MouseEventArgs e)
{
mouseDown=false;
AssociatedObject.Child.ReleaseMouseCapture();
}
}
就像MapCanvas一样,如果我们压缩鼠标左键,移动鼠标,然后释放鼠标左键,我们希望弹出窗口在屏幕上拖动。相反,当我尝试左键单击并拖动时,MapCanvas会被拖动,如下所示:
在这里,我在看一张地图;单击蓝色点打开弹出窗口。
我刚打开我的弹夹,准备把它拖到一边
您可以看到,减去裁剪的抖动,我的弹出窗口仍然保留在原来的位置,而我的地图被拖动了
在我的屏幕截图中没有提到的是一旦我放开鼠标左键弹出窗口的“粘性”行为:此时弹出窗口将开始拖动,我只能通过双击来摆脱它
如果你能做到这一点,我祝贺你。我只能希望,在理解我的问题的同时,也能有如此大的耐心,你也可以
private void MouseLeftButtonDown(object sender, MouseEventArgs e)
{
mouseDown = true;
oldMousePosition = AssociatedObject.PointToScreen(e.GetPosition(AssociatedObject));
AssociatedObject.Child.CaptureMouse();
e.Handled = true;
}