WPF-利用装饰器实现控件的自由拖动

这篇具有很好参考价值的文章主要介绍了WPF-利用装饰器实现控件的自由拖动。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

  在项目中经常会遇到类似如下要求的需求,创建允许自由拖动的控件,这样的需求可以使用WPF的装饰器Adorner来实现。

WPF-利用装饰器实现控件的自由拖动

 文章来源地址https://www.toymoban.com/news/detail-671021.html

一、什么是装饰器?

装饰器是一种特殊类型的FrameworkElement,装饰器始终呈现在被装饰元素的顶部,用于向用户提供可视化提示。装饰器可以在不改变原有控件结构的基础上,将功能点增加到元素中或元素上提供视觉效果等,如WPF的光标效果,焦点效果等都是通过装饰器来实现的。
装饰器是一个始终位于装饰元素或装饰元素集合顶部的呈现图层,其呈现独立与它所绑定的UIElement,WPF中的装饰器是在一个单独的曾AnornerLayer上进行绘制的,该层位于普通控件元素之上,而且允许多个AdornerLayer进行叠加,当加入AdornerLayer层后,Adorner会默认使用其所装饰元素的左上角作为原点进行定位。
  • Adorner 是一个抽象类,所有装饰器的实现都需要继承此类,比如ThumbBorderAdorner
  • AdornerLayer 一个类,表示一个或多个装饰元素的装饰器呈现层
    • 利用AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(userControl)函数,来获取指定控件是否有装饰器布局层
    • 利用Adorner[] adorners = adornerLayer.GetAdorners(userControl);,来查看当前控件的装饰器个数
  • AdornerDecorator 一个类,为可视化树中的子元素提供AdornerLayer
WPF-利用装饰器实现控件的自由拖动

二、装饰器的使用场景

  • 为现有的元素添加额外的装饰,如为Border添加8个装饰矩形
 

三、如何创建自定义的装饰器?

  • 创建一个类,继承自Adorner类
  • 重写此类中需要的函数
    • OnRender(DrawingContext drawingContext) 在派生类中重写,参与由布局系统控制的呈现操作,调用此方法时,不直接使用此元素的呈现指令,而是将其保留供布局和绘制在以后异步使用,可以使用drawingContext 来绘制各种形状以及图形。
    • ArrangeOverride() 为FrameworkElement派生类定位子元素并确定大小,在其中调用Arrange()函数,来定位子元素
    • GetVisualChild() //获取第几个Thumb控件,在构造时使用
  • 简单的装饰可以重写OnRender()函数,在其中绘制所需要的装饰,参照BorderAdorner
  • 复杂一些的如需要可以定义VisualCollection的集合来存放装饰器,重写ArrangeOverride和GetVisualChild函数来实现,参照ThumbBorderAdorner
 

四、给控件使用自定义的Adorner

  • 添加Adorner
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(userControl);
if (adornerLayer != null)
{
    Adorner[] adorners = adornerLayer.GetAdorners(userControl);
    if (adorners == null || adorners.Count() == 0)
    {
        adornerLayer.Add(new ThumbBorderAdorner(userControl)
        {
            DragCompletedAction = ThumbBorderAdornerDragCompletedActionFunc
        });
    }
}

 

  • 移除 Adorner
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(userControl);
if (adornerLayer != null)
{
    Adorner[] adorners = adornerLayer.GetAdorners(userControl);
    if (adorners != null && adorners.Count() > 0)
        adornerLayer.Remove(adorners[0]);
}

 

五、处理拖拽Thumb时,导致控件范围超出父级容器的情况

  • 即在添加装饰器的控件中添加UserControl_SizeChanged()来处理控件大小和和未知变化
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
    int tempMargin = 1;  //MarkRectUserControl控件始终在父级容器的1个像素以内

    double left = Canvas.GetLeft(this);
    if (left < tempMargin)
    {
        left = tempMargin;
        Canvas.SetLeft(this, left);
    }

    double top = Canvas.GetTop(this);
    if (top < tempMargin)
    {
        top = tempMargin;
        Canvas.SetTop(this, top);
    }

    if (left + this.ActualWidth > canvasParent.ActualWidth - tempMargin)
        this.Width = canvasParent.ActualWidth - tempMargin - left;

    if (top + this.ActualHeight > canvasParent.ActualHeight - tempMargin)
        this.Height = canvasParent.ActualHeight - tempMargin - top;

}

 

六、测试使用

 

<UserControl x:Class="BlogDemo.Views.AdornerTestUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:BlogDemo.Views"
             mc:Ignorable="d" 
             Background="White"
             d:DesignHeight="450" d:DesignWidth="800"
             FontSize="20"
             Foreground="Blue"
             Loaded="UserControl_Loaded"
             >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <TextBlock Text="请拖拽Thumb控件来改变,控件大小。" HorizontalAlignment="Center" Margin="10"/>

        <Canvas x:Name="Canvas_Main" Grid.Row="1">
            <Border x:Name="Border_Text" Canvas.Left="200" Canvas.Top="100" Width="200" Height="100" BorderThickness="2" BorderBrush="Green" SizeChanged="Border_Text_SizeChanged"/>
        </Canvas>
    </Grid>
</UserControl>
/// <summary>
/// AdornerTestUserControl.xaml 的交互逻辑
/// </summary>
public partial class AdornerTestUserControl : UserControl
{
    public AdornerTestUserControl()
    {
        InitializeComponent();
    }

    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(Border_Text);
        if (adornerLayer != null)
        {
            Adorner[] adorners = adornerLayer.GetAdorners(Border_Text);
            if (adorners == null || adorners.Count() == 0)
            {
                adornerLayer.Add(new ThumbBorderAdorner(Border_Text));
            }
        }
    }

    private void Border_Text_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        int tempMargin = 100; 

        double left = Canvas.GetLeft(Border_Text);
        if (left < tempMargin)
        {
            left = tempMargin;
            Canvas.SetLeft(Border_Text, left);
        }

        double top = Canvas.GetTop(Border_Text);
        if (top < tempMargin)
        {
            top = tempMargin;
            Canvas.SetTop(Border_Text, top);
        }

        if (Border_Text.ActualWidth < tempMargin)
            Border_Text.Width = tempMargin;

        if (Border_Text.ActualHeight < tempMargin)
            Border_Text.Height = tempMargin;

        if (left + Border_Text.ActualWidth > Canvas_Main.ActualWidth - tempMargin)
            Border_Text.Width = Canvas_Main.ActualWidth - tempMargin - left;

        if (top + Border_Text.ActualHeight > Canvas_Main.ActualHeight - tempMargin)
            Border_Text.Height = Canvas_Main.ActualHeight - tempMargin - top;
    }
}

 

 

源码地址:https://gitee.com/LiuShuiRuoBing/code_blog

 

 

到了这里,关于WPF-利用装饰器实现控件的自由拖动的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C#在winForm窗体中添加一个可以自由拖动的控件

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 目录 文章目录 一、实现步骤 1.创建一个新的Windows窗体项目 2.添加控件如图 3.代码部分 总结 textBox1=鼠标在需要拖动的控件中的坐标 X 值 textBox2=鼠标在需要拖动的控件中的坐标 Y 值 textBox3=需要

    2024年01月19日
    浏览(44)
  • 浅谈WPF之控件拖拽与拖动

    使用过office的visio软件画图的小伙伴都知道,画图软件分为两部分,左侧图形库,存放各种图标,右侧是一个画布,将左侧图形库的图标控件拖拽到右侧画布,就会生成一个新的控件,并且可以自由拖动。那如何在WPF程序中,实现类似的功能呢?今天就以一个简单的小例子,

    2024年02月05日
    浏览(59)
  • vue/Element UI 实现Element UI el-dialog 自由拖动

    前言: 最近有个项目,客户要求弹窗可拖动,但是由于elemen ui本身的弹窗并没有拖动的属性,无法满足客户的需求。 于是我百度找到了几篇文章,终于可以实现客户的需求! 请往下看↓↓ 一、新建一个目录:utils 二、创建drag .js文件 三、创建directive.js 文件 四、main.js文件中

    2024年02月02日
    浏览(66)
  • Flutter 实现任意控件拖动

    使用flutter开发是需要控件能拖动,比如画板中的元素,或者工具条,搜索框,每个都单独去实现拖动还是比较麻烦的,将拖动功能封装成一个控件,需要的时候直接使用拖动控件作为父控件这样就方便很多了。 使用translate变换位置即可 这一步不是必须的,但是如果需要限制

    2024年02月15日
    浏览(44)
  • 利用colab实现AI绘画自由

    最近AIGC真的很火,除了chatGPT外,AI绘画也是热度不减。最近也是决定抽空上手尝试一下,但奈何我的本本太渣,丐版Mac跑跑数据还行,跑Stable Diffusion根本没戏。所以还是决定白嫖谷歌的colab。 网上关于本地部署的教程很多,最火的例如b站的秋葉大神,mac版的也不少,可自行

    2024年02月09日
    浏览(43)
  • Android:RecyclerView自由拖动item

    原生就自带有可拖动item的工具:ItemTouchHelper 看下效果: 可拖动RecyclerView预览效果 接下来我们看如何使用。 其中判断条件中的item.isMovable这边是记录该item是否可以拖动,也可以换成其他判断条件比如根据位置判断等。 另外,需要留意一点,如果你是在onBindViewHolder中有设置点

    2024年01月23日
    浏览(47)
  • Mkdocs中利用Js实现大小圈鼠标拖动样式

    在 docs/javascripts/extra.js 下复制粘贴: 其中比较重要的参数就是鼠标的尺寸和颜色,已经在上图中标出,目前发现颜色只支持RGB写法和固有名称写法(例如red这种),其他参数也可以自行摸索: 在docs/stylesheets/extra.css添加如下代码: 这里比较重要的参数就是鼠标跟随的圆形颜

    2024年02月15日
    浏览(37)
  • WPF 实现 Message 消息提醒控件

    WPF 实现 Message 消息提醒控件 控 件:Message 作 者:WPFDevelopersOrg - 驚鏵 原文链接:https://github.com/WPFDevelopersOrg/WPFDevelopers 框架使用 .NET4 至 .NET6 ; Visual Studio 2022 ; 接着上一篇 1)新增 MessageListBoxItem.cs 代码如下: 新增了名为 MessageType 的依赖属性,类型为 MessageBoxImage ,默认值为

    2024年02月16日
    浏览(35)
  • WPF 组态软件实现思路(WPF控件可视化布局)

    一、实现控件选中及自由拖动 二、实现控件对齐功能 三、实现对齐辅助线功能 四、实现框选功能 GitHub地址点此 属性编辑控件基于Devexpress V21.2.3 控件库,如需编译需购买及安装 Devexpress V21.2.3 开发库 脚本编辑基于AvalonEdit开源库 https://github.com/icsharpcode/AvalonEdit 图标控件基于

    2024年02月04日
    浏览(69)
  • WPF实现html中的table控件

    前言 相信很多做WPF开发的小伙伴都遇到过表格类的需求,虽然现有的Grid控件也能实现,但是使用起来的体验感并不好,比如要实现一个Excel中的表格效果,估计你能想到的第一个方法就是套Border控件,用这种方法你需要控制每个Border的边框,并且在一堆Bordr中找到Grid.Row,G

    2024年03月26日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包