C# wpf 无边框窗口实现拖动调整大小

2024-08-29 05:48

本文主要是介绍C# wpf 无边框窗口实现拖动调整大小,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

WPF拖动改变大小系列

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


文章目录

  • WPF拖动改变大小系列
  • 前言
  • 一、如何实现?
    • 1.继承Adorner
    • 2.使用Thumb
    • 3.实现拖动逻辑
  • 二、完整代码
  • 三、使用示例
  • 总结


前言

在《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);      
}

2.使用Thumb

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

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

初始化

 public WindowResizeAdorner(UIElement adornedElement) : base(adornedElement){//初始化thumb_leftThumb = new Thumb();_leftThumb.HorizontalAlignment = HorizontalAlignment.Left;_leftThumb.VerticalAlignment = VerticalAlignment.Center;_leftThumb.Cursor = Cursors.SizeWE;//其他略...
}

3.实现拖动逻辑

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

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

二、完整代码

代码如下:

   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;}}

三、使用示例

示例代码如下:

<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>

在窗口或控件的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));
}

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


总结

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

这篇关于C# wpf 无边框窗口实现拖动调整大小的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1117016

相关文章

Android实现悬浮按钮功能

《Android实现悬浮按钮功能》在很多场景中,我们希望在应用或系统任意界面上都能看到一个小的“悬浮按钮”(FloatingButton),用来快速启动工具、展示未读信息或快捷操作,所以本文给大家介绍... 目录一、项目概述二、相关技术知识三、实现思路四、整合代码4.1 Java 代码(MainActivi

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

基于Python实现读取嵌套压缩包下文件的方法

《基于Python实现读取嵌套压缩包下文件的方法》工作中遇到的问题,需要用Python实现嵌套压缩包下文件读取,本文给大家介绍了详细的解决方法,并有相关的代码示例供大家参考,需要的朋友可以参考下... 目录思路完整代码代码优化思路打开外层zip压缩包并遍历文件:使用with zipfile.ZipFil

Python实现word文档内容智能提取以及合成

《Python实现word文档内容智能提取以及合成》这篇文章主要为大家详细介绍了如何使用Python实现从10个左右的docx文档中抽取内容,再调整语言风格后生成新的文档,感兴趣的小伙伴可以了解一下... 目录核心思路技术路径实现步骤阶段一:准备工作阶段二:内容提取 (python 脚本)阶段三:语言风格调

C#实现将Excel表格转换为图片(JPG/ PNG)

《C#实现将Excel表格转换为图片(JPG/PNG)》Excel表格可能会因为不同设备或字体缺失等问题,导致格式错乱或数据显示异常,转换为图片后,能确保数据的排版等保持一致,下面我们看看如何使用C... 目录通过C# 转换Excel工作表到图片通过C# 转换指定单元格区域到图片知识扩展C# 将 Excel

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QGroupBox控件的实现

《Qt中QGroupBox控件的实现》QGroupBox是Qt框架中一个非常有用的控件,它主要用于组织和管理一组相关的控件,本文主要介绍了Qt中QGroupBox控件的实现,具有一定的参考价值,感兴趣... 目录引言一、基本属性二、常用方法2.1 构造函数 2.2 设置标题2.3 设置复选框模式2.4 是否

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法

《springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法》:本文主要介绍springboot整合阿里云百炼DeepSeek实现sse流式打印,本文给大家介绍的非常详细,对大... 目录1.开通阿里云百炼,获取到key2.新建SpringBoot项目3.工具类4.启动类5.测试类6.测