C# 我的可拖动弹出窗口也会拖动拥有它们的视觉元素。我怎样才能解决这个问题?

C# 我的可拖动弹出窗口也会拖动拥有它们的视觉元素。我怎样才能解决这个问题?,c#,wpf,C#,Wpf,更新:我发现,如果我总是从地图画布中的OnMouseLeftButtonDown返回,我就能够按照我想要的方式使用弹出窗口。这向我表明,MapCanvas的行为正在阻止罪犯。我可能很快就能找到问题的答案 我担心导致这个问题的最终问题一直没有解决,所以我将尽可能多地记录我的工作。很抱歉这是一篇很长的帖子,但我想尽可能清楚地分享我所拥有的。下面是我面临的问题的摘要: 我有一个由地图线包含的弹出窗口,它本身包含在地图中。当用户左键单击并拖动时,它将拖动地图。我写了一个行为来点击并拖动弹出窗口。当我左键

更新:我发现,如果我总是从地图画布中的OnMouseLeftButtonDown返回,我就能够按照我想要的方式使用弹出窗口。这向我表明,MapCanvas的行为正在阻止罪犯。我可能很快就能找到问题的答案

我担心导致这个问题的最终问题一直没有解决,所以我将尽可能多地记录我的工作。很抱歉这是一篇很长的帖子,但我想尽可能清楚地分享我所拥有的。下面是我面临的问题的摘要:

我有一个由地图线包含的弹出窗口,它本身包含在地图中。当用户左键单击并拖动时,它将拖动地图。我写了一个行为来点击并拖动弹出窗口。当我左键单击弹出窗口并尝试拖动它时,我会拖动地图-弹出窗口保持静止。当我松开鼠标左键时,弹出窗口就会“卡”在我的光标上,它会拖到我移动鼠标的任何地方

好了,现在我们来详细介绍一下:

我已经编写了一个用于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
        }
    }
}
我共享覆盖,因为它们是我处理地图交互的方式,如拖动地图、双击缩放等。我还认为它在导致问题的原因中起着作用

我还编写了一个名为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;
        }