zoukankan      html  css  js  c++  java
  • WPF Popup实现拖动

    问题一.popup总是置顶,遮挡其他窗口


    最近发现popup设置打开后,总是会遮挡其他窗口,而我们只想让它仅仅在应用程序的上一层即可,并不像让它在最上面

    解决方案是继承Popup重新定义控件PopupEx。

    public class PopupEx : Popup
        {
            public static DependencyProperty TopmostProperty = Window.TopmostProperty.AddOwner(typeof(PopupEx ), new FrameworkPropertyMetadata(false, 
    OnTopmostChanged));
            public bool Topmost
            {
                get { return (bool)GetValue(TopmostProperty); }
                set { SetValue(TopmostProperty, value); }
            }
            private static void OnTopmostChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
            {
                (obj as PopupEx ).UpdateWindow();
            }
            protected override void OnOpened(EventArgs e)
            {
                UpdateWindow();
            }
            private void UpdateWindow()
            {
                var hwnd = ((HwndSource)PresentationSource.FromVisual(this).Handle;
                RECT rect;
                if (GetWindowRect(hwnd, out rect))
                {
                    SetWindowPos(hwnd, Topmost ? -1 : -2, rect.Left, rect.Top, (int)this.Width, (int)this.Height, 0);
                }
            }
            #region imports definitions
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
            }
            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
            [DllImport("user32", EntryPoint = "SetWindowPos")]
            private static extern int SetWindowPos(IntPtr hWnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags);
            #endregion
        }

    然后在调用该控件的时候设置该PopupEx的属性 Topmost=False即可。


    以上方法来自 Leaco 的博客:http://www.cnblogs.com/Leaco


    但是,呵呵,然并软,在new该popupEx的时侯设置topmost=false之后,还是会置顶

    后来再加上了一句代码即可解决这个问题:就是在将popupEx加入到某个panel或者父容器当中,因为popup的parent的只读的,无法赋值,

    所以我就让一个dockpanel.Children.Add(popupEx),配合PopupEx类,就完美解决了该问题。



    ************2016.11.16******************************

    问题二.popup无法跟随主窗体移动或者更新状态

    后来发现这个popup随着窗体移动不会消失,网上流传的方法就是在主窗体的locationchanged事件和sizechanged事件里面

    回调一个函数,代码如下:

      Loaded += (sender, e) =>
                  {
                      Window window = Window.GetWindow(this);
                      window.LocationChanged += HandleMovePopup;
                      window.SizeChanged += HandleMovePopup;
                  };

     void HandleMovePopup(object sender, EventArgs e)
            {
                if (NewMsgPop != null && NewMsgPop.IsOpen)
                {
                    var mi = typeof(Popup).GetMethod("UpdatePosition", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                    mi.Invoke(NewMsgPop, null);
                }
            }
    是可以解决这个移动窗体的问题。然并软,还有更坑爹的事情,当程序不在最顶部,既有其他应用程序在最顶部时,

    此时再让popup.isopen=true时,还是会显示在其他应用程序之前。。。。。。。。。。

    真是欲哭无泪,最后的解决方案是:改成一个label, 通过设置Gird.SetZindex(label,0)或者Gird.SetZindex(label,2)来控制label的显隐。

    前提是将label放进一个Grid里面

    至此,这个功能需求算是圆满完成了,留给我的启发是,以后能不用popup尽量不用。。。。。。。


    当然肯定有办法能解决这个问题,迫于项目压力,没有时间去细究,

    当然如果有高人能说出更厉害的方法来解决这个问题,希望能赐教!



    ************2016.11.24******************************

    问题三:Popup如何拖动

    有几个思路,第一,是得到鼠标位置,然后通过API发消息给popup通知其修改自己的位置,第二是在mousemove事件里直接修改popup的位置。

    第一种方法可参考该博客:http://www.cnblogs.com/lisweden/p/3183476.html

    然后介绍第二种方法:

    要引用 system.windows.itneractivity.dll

    然后新建class

      public class popup_dragmove_behavior : Behavior<Popup>
        {
            public bool _mouse_down;
            Point _old_pos;
    
            Point _orignal_pos;
            double max_vertical_offset;
            public popup_dragmove_behavior()
            {
    
            }
            protected override void OnAttached()
            {
                base.OnAttached();
    
                AssociatedObject.MouseLeftButtonDown += (sender, e) =>
                {
                    mouse_left_button_down(sender, e);
                };
                AssociatedObject.MouseLeftButtonUp += (sender, e) =>
                {
                    mouse_left_button_up(sender, e);
                };
                AssociatedObject.MouseMove += (sender, e) =>
                {
                    mouse_move(sender, e);
                };
                AssociatedObject.Closed += (sender, e) =>
                {
                    popup_close(sender, e);
                };
            }
    
            protected override void OnDetaching()
            {
                base.OnDetaching();
                AssociatedObject.MouseLeftButtonDown -= (sender, e) =>
                {
                    mouse_left_button_down(sender, e);
                };
                AssociatedObject.MouseLeftButtonUp -= (sender, e) =>
                {
                    mouse_left_button_up(sender, e);
                };
                AssociatedObject.MouseMove -= (sender, e) =>
                {
                    mouse_move(sender, e);
                };
                AssociatedObject.Closed -= (sender, e) =>
                {
                    popup_close(sender, e);
                };
            }
    
            void mouse_left_button_down(Object sender, MouseButtonEventArgs e)
            {
                _mouse_down = true;
                if (AssociatedObject.VerticalOffset == 0)
                {
                    _orignal_pos = AssociatedObject.Child.PointToScreen(new Point(AssociatedObject.ActualWidth, 0));
                    max_vertical_offset = 0 - _orignal_pos.Y;
                }
                _old_pos = AssociatedObject.Child.PointToScreen(e.GetPosition(AssociatedObject.Child));
                AssociatedObject.Child.CaptureMouse();
            }
    
            void mouse_move(Object sender, MouseEventArgs e)
            {
                if (!_mouse_down)
                {
                    return;
                }
                var child_pos = e.GetPosition(AssociatedObject.Child);
                var new_pos = AssociatedObject.Child.PointToScreen(child_pos);
                var offset = new_pos - _old_pos;
                _old_pos = new_pos;
                AssociatedObject.HorizontalOffset += offset.X;
                var new_VerticalOffset = AssociatedObject.VerticalOffset + offset.Y;
                if (new_VerticalOffset < max_vertical_offset)
                {
                    new_VerticalOffset = max_vertical_offset;
                }
                AssociatedObject.VerticalOffset = new_VerticalOffset;
            }
    
            void mouse_left_button_up(Object sender, MouseButtonEventArgs e)
            {
                _mouse_down = false;
                AssociatedObject.Child.ReleaseMouseCapture();
            }
    
            void popup_close(Object sender, EventArgs e)
            {
                AssociatedObject.HorizontalOffset = 0;
                AssociatedObject.VerticalOffset = 0;
            }
        }



    然后这样调用即可:

    popup_dragmove_behavior  be=new popup_dragmove_behavior();

    be.Attch(your_popup);

    但是这个方法有个缺点是,无法将popup拖出屏幕之外

    总结:除非真的非popup不可,那么一般情况下,直接用window会省事很多。。。。。。再见


  • 相关阅读:
    iOS开发-文件管理(一)
    浅析栈区和堆区内存分配的区别
    浅谈Block传值-匿名函数(代码块)
    cell的各种使用和赋值 总结
    类方法和对象方法的区别
    属性传值 ,代理传值,单例
    类目,延展,协议
    任意点 并查集
    Codeforces 145E. Lucky Queries 线段树
    Codeforces 103B. Cthulhu 并查集运用
  • 原文地址:https://www.cnblogs.com/kevinWu7/p/10163547.html
Copyright © 2011-2022 走看看