Make WPF window draggable, no matter what element is clicked

前端 未结 9 1019
灰色年华
灰色年华 2020-12-04 07:47

My question is 2 fold, and I am hoping there are easier solutions to both provided by WPF rather than the standard solutions from WinForms (which Christophe

9条回答
  •  庸人自扰
    2020-12-04 08:14

    Sometimes, we do not have access to Window, e.g. if we are using DevExpress, all that is available is a UIElement.

    Step 1: Add attached property

    The solution is to:

    1. Hook into MouseMove events;
    2. Search up the visual tree until we find the first parent Window;
    3. Call .DragMove() on our newly discovered Window.

    Code:

    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    
    namespace DXApplication1.AttachedProperty
    {
        public class EnableDragHelper
        {
            public static readonly DependencyProperty EnableDragProperty = DependencyProperty.RegisterAttached(
                "EnableDrag",
                typeof (bool),
                typeof (EnableDragHelper),
                new PropertyMetadata(default(bool), OnLoaded));
    
            private static void OnLoaded(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                var uiElement = dependencyObject as UIElement;
                if (uiElement == null || (dependencyPropertyChangedEventArgs.NewValue is bool) == false)
                {
                    return;
                }
                if ((bool)dependencyPropertyChangedEventArgs.NewValue  == true)
                {
                    uiElement.MouseMove += UIElementOnMouseMove;
                }
                else
                {
                    uiElement.MouseMove -= UIElementOnMouseMove;
                }
    
            }
    
            private static void UIElementOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
            {
                var uiElement = sender as UIElement;
                if (uiElement != null)
                {
                    if (mouseEventArgs.LeftButton == MouseButtonState.Pressed)
                    {
                        DependencyObject parent = uiElement;
                        int avoidInfiniteLoop = 0;
                        // Search up the visual tree to find the first parent window.
                        while ((parent is Window) == false)
                        {
                            parent = VisualTreeHelper.GetParent(parent);
                            avoidInfiniteLoop++;
                            if (avoidInfiniteLoop == 1000)
                            {
                                // Something is wrong - we could not find the parent window.
                                return;
                            }
                        }
                        var window = parent as Window;
                        window.DragMove();
                    }
                }
            }
    
            public static void SetEnableDrag(DependencyObject element, bool value)
            {
                element.SetValue(EnableDragProperty, value);
            }
    
            public static bool GetEnableDrag(DependencyObject element)
            {
                return (bool)element.GetValue(EnableDragProperty);
            }
        }
    }
    

    Step 2: Add Attached Property to any element to let it drag the window

    The user can drag the entire window by clicking on a specific element, if we add this attached property:

    
        
    
    

    Appendix A: Optional Advanced Example

    In this example from DevExpress, we replace the title bar of a docking window with our own grey rectangle, then ensure that if the user clicks and drags said grey rectagle, the window will drag normally:

    
    
        
            
                
                    
                        
                            
                                
                                
                            
                            
                                
                            
                            
                        
                    
                
            
        
    
    

    Disclaimer: I am not affiliated with DevExpress. This technique will work with any user element, including standard WPF or Telerik (another fine WPF library provider).

提交回复
热议问题