当前位置:   article > 正文

C# wpf 无边框窗口实现拖动调整大小_wpf window 拖动和拖动改变大小

wpf window 拖动和拖动改变大小

WPF拖动改变大小系列

第一节 Grid内控件拖动调整大小
第二节 Canvas内控件拖动调整大小
第三节 窗口拖动调整大小(本章)
第四节 附加属性实现拖动调整大小
第五章 拓展更多调整大小功能



前言

《C# wpf Grid中实现控件拖动调整大小》中我们实现了Grid中的控件动态调整大小,对于自定义的无边框窗口也可以使用类似的方式实现。虽然能查到的方案有通过Window Api的和通过WindowChrome实现的,一个是对系统有依赖还一个是依赖.net版本,这里提供一种相对轻量的实现方法。


一、如何实现?

1.继承Adorner

通过装饰器的方式添加8个方位拖动区域在窗口上,这样既可以不影响控件布局,又可以自由摆放8个拖动控件。通过重写方法,给装饰添加控件。必要的重写的方法如下面示例所示:

public class WindowResizeAdorner : Adorner
{
  //获取装饰器的元素个数
  protected override Visual GetVisualChild(int index);
  //指定装饰器子元素个数
  protected override int VisualChildrenCount{get;}
  //布局,添加的子元素需要手动布局。
  protected override Size ArrangeOverride(Size finalSize);      
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

2.使用Thumb

因为Thumb实现拖动比较容易,有相关事件获取拖动距离。在装饰器中定义8个Thumb,对应8个方位点。
示例代码如下:

//4条边
Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
//4个角
Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
  • 1
  • 2
  • 3
  • 4

初始化

 public WindowResizeAdorner(UIElement adornedElement) : base(adornedElement)
 {
     //初始化thumb
     _leftThumb = new Thumb();
     _leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
     _leftThumb.VerticalAlignment = VerticalAlignment.Center;
     _leftThumb.Cursor = Cursors.SizeWE;
     //其他略...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.实现拖动逻辑

在Thumb的DragDelta事件可以获取拖动距离,根据八个方位的不同计算并修改控件的大小。

private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
//1.右侧点HorizontalChange加宽
//2.左侧点HorizontalChange减宽,HorizontalChange加左移
//3.下侧点VerticalChange加高
//4.上侧点VerticalChange减高,VerticalChange加上移
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

二、完整代码

代码如下:

   public class WindowResizeAdorner : Adorner
    {
        //4条边
        Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
        //4个角
        Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
        //布局容器,如果不使用布局容器,则需要给上述8个控件布局,实现和Grid布局定位是一样的,会比较繁琐且意义不大。
        Grid _grid;
        UIElement _adornedElement;
        Window _window;
        public WindowResizeAdorner(UIElement adornedElement) : base(adornedElement)
        {
            _adornedElement = adornedElement;
            _window = Window.GetWindow(_adornedElement);
            //初始化thumb
            _leftThumb = new Thumb();
            _leftThumb.HorizontalAlignment = HorizontalAlignment.Left;
            _leftThumb.VerticalAlignment = VerticalAlignment.Stretch;
            _leftThumb.Cursor = Cursors.SizeWE;
            _topThumb = new Thumb();
            _topThumb.HorizontalAlignment = HorizontalAlignment.Stretch;
            _topThumb.VerticalAlignment = VerticalAlignment.Top;
            _topThumb.Cursor = Cursors.SizeNS;
            _rightThumb = new Thumb();
            _rightThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightThumb.VerticalAlignment = VerticalAlignment.Stretch;
            _rightThumb.Cursor = Cursors.SizeWE;
            _bottomThumb = new Thumb();
            _bottomThumb.HorizontalAlignment = HorizontalAlignment.Stretch;
            _bottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _bottomThumb.Cursor = Cursors.SizeNS;
            _lefTopThumb = new Thumb();
            _lefTopThumb.HorizontalAlignment = HorizontalAlignment.Left;
            _lefTopThumb.VerticalAlignment = VerticalAlignment.Top;
            _lefTopThumb.Cursor = Cursors.SizeNWSE;
            _rightTopThumb = new Thumb();
            _rightTopThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightTopThumb.VerticalAlignment = VerticalAlignment.Top;
            _rightTopThumb.Cursor = Cursors.SizeNESW;
            _rightBottomThumb = new Thumb();
            _rightBottomThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightBottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _rightBottomThumb.Cursor = Cursors.SizeNWSE;
            _leftbottomThumb = new Thumb();
            _leftbottomThumb.HorizontalAlignment = HorizontalAlignment.Left;
            _leftbottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _leftbottomThumb.Cursor = Cursors.SizeNESW;
            _grid = new Grid();
            _grid.Children.Add(_leftThumb);
            _grid.Children.Add(_topThumb);
            _grid.Children.Add(_rightThumb);
            _grid.Children.Add(_bottomThumb);
            _grid.Children.Add(_lefTopThumb);
            _grid.Children.Add(_rightTopThumb);
            _grid.Children.Add(_rightBottomThumb);
            _grid.Children.Add(_leftbottomThumb);
            AddVisualChild(_grid);
            foreach (Thumb thumb in _grid.Children)
            {
                int thumnSize = 10;
                if (thumb.HorizontalAlignment == HorizontalAlignment.Stretch)
                {
                    thumb.Width = double.NaN;
                    thumb.Margin = new Thickness(thumnSize, 0, thumnSize, 0);
                }
                else
                {
                    thumb.Width = thumnSize;
                }
                if (thumb.VerticalAlignment == VerticalAlignment.Stretch)
                {
                    thumb.Height = double.NaN;
                    thumb.Margin = new Thickness(0, thumnSize, 0, thumnSize);
                }
                else
                {
                    thumb.Height = thumnSize;
                }
                thumb.Background = Brushes.Green;
                thumb.Template = new ControlTemplate(typeof(Thumb))
                {
                    VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent))
                };
                thumb.DragDelta += Thumb_DragDelta;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            return _grid;
        }
        protected override int VisualChildrenCount
        {
            get
            {
                return 1;
            }
        }
        protected override Size ArrangeOverride(Size finalSize)
        {
            //直接给grid布局,grid内部的thumb会自动布局。
            _grid.Arrange(new Rect(new Point(-(_window.RenderSize.Width - finalSize.Width) / 2, -(_window.RenderSize.Height - finalSize.Height) / 2), _window.RenderSize));
            return finalSize;
        }
        //拖动逻辑
        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            var c = _window;
            var thumb = sender as FrameworkElement;
            double left, top, width, height;
            if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
            {
                left = c.Left + e.HorizontalChange;
                width = c.Width - e.HorizontalChange;
            }
            else
            {
                left = c.Left;
                width = c.Width + e.HorizontalChange;
            }
            if (thumb.HorizontalAlignment != HorizontalAlignment.Stretch)
            {
                if (width > 63)
                {               
                    c.Left = left;
                    c.Width = width;              
                }
            }
            if (thumb.VerticalAlignment == VerticalAlignment.Top)
            {

                top = c.Top + e.VerticalChange;
                height = c.Height - e.VerticalChange;
            }
            else
            {
                top = c.Top;
                height = c.Height + e.VerticalChange;
            }

            if (thumb.VerticalAlignment != VerticalAlignment.Stretch)
            {
                if (height > 63)
                {
                    c.Top = top;
                    c.Height = height;
                }
            }
        }
        //thumb的样式
        FrameworkElementFactory GetFactory(Brush back)
        {
            var fef = new FrameworkElementFactory(typeof(Rectangle));
            fef.SetValue(Rectangle.FillProperty, back);
            return fef;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157

三、使用示例

示例代码如下:

<Window x:Class="WpfControlMove.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfControlMove"
        mc:Ignorable="d"
        Title="MainWindow" Height="360" Width="640"    
        Loaded="Window_Loaded"      
        WindowStyle="None"
        ResizeMode="NoResize"
        Background="Transparent"    
        AllowsTransparency="True"
        >
    <Border Margin="10" Background="White">
        <Border.Effect>
            <DropShadowEffect Color="#FFAAAAAA" ShadowDepth="0" BlurRadius="10" Opacity="0.4"/>
        </Border.Effect>
    </Border>
</Window>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在窗口或控件的Loaded事件中添加装饰器:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    //将装饰器添加到窗口的Content控件上
    var c = this.Content as UIElement;
    var layer = AdornerLayer.GetAdornerLayer(c);
    layer.Add(new WindowResizeAdorner(c));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

效果预览:
在这里插入图片描述


总结

以上就是今天要讲的内容,本文讲述了自定义无边框窗口实现拖动改变大小的方法,其有优点是轻量易于实现和使用,但是也有缺点,往左和往上拖动时会出现一定的界面闪烁,但总得来说,这种实现方法还是可以使用的。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/511845
推荐阅读
相关标签
  

闽ICP备14008679号