首页 > 其他分享 >Avalonia封装实现指定组件允许拖动的工具类

Avalonia封装实现指定组件允许拖动的工具类

时间:2024-11-07 10:57:37浏览次数:3  
标签:封装 拖动 UserControl using Avalonia public DragDemo

创建Avalonia的MVVM项目,命名DragDemo,然后将项目的Nuget包更新到预览版

 
1 2 3 4 5 6 7 8 <ItemGroup>         <PackageReference Include="Avalonia" Version="11.0.0-preview5" />         <PackageReference Include="Avalonia.Desktop" Version="11.0.0-preview5" />         <!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->         <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.0-preview5" />         <PackageReference Include="Avalonia.ReactiveUI" Version="11.0.0-preview5" />         <PackageReference Include="XamlNameReferenceGenerator" Version="1.5.1" />     </ItemGroup>
更新完成以后ViewLocatorApp.axaml会报错,
修改ViewLocator.cs为下面的代码
 
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 using System; using Avalonia.Controls; using Avalonia.Controls.Templates; using DragDemo.ViewModels; namespace DragDemo; public class ViewLocator : IDataTemplate {     /// <summary>     /// 将IControl修改成Control     /// </summary>     /// <param name="data"></param>     /// <returns></returns>     public Control Build(object data)     {         var name = data.GetType().FullName!.Replace("ViewModel", "View");         var type = Type.GetType(name);         if (type != null)         {             return (Control)Activator.CreateInstance(type)!;         }         return new TextBlock { Text = "Not Found: " + name };     }     public bool Match(object data)     {         return data is ViewModelBase;     } }
添加Avalonia.Themes.Fluent,因为预览版本的包已经独立需要单独安装
 
1 <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview5" />
打开App.axaml文件,修改为以下代码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 <Application xmlns="https://github.com/avaloniaui"              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"              xmlns:local="using:DragDemo"              RequestedThemeVariant="Light"              x:Class="DragDemo.App">     <Application.DataTemplates>         <local:ViewLocator/>     </Application.DataTemplates>     <Application.Styles>         <FluentTheme DensityStyle="Compact"/>     </Application.Styles>       </Application>
打开Views/MainWindow.axaml
在头部添加以下代码,让窗口无边框,设置指定窗口Height="38" Width="471",参数让其不要占用整个屏幕,
 
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 <Window xmlns="https://github.com/avaloniaui"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         xmlns:vm="using:DragDemo.ViewModels"         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"         mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"         x:Class="DragDemo.Views.MainWindow"         Icon="/Assets/avalonia-logo.ico"         ExtendClientAreaToDecorationsHint="True"         ExtendClientAreaChromeHints="NoChrome"         ExtendClientAreaTitleBarHeightHint="-1"         MaxHeight="38" MaxWidth="471"         Title="DragDemo">     <Window.Styles>         <Style Selector="Window">             <Setter Property="BorderThickness" Value="0"/>             <Setter Property="Padding" Value="0"/>             <Setter Property="Background" Value="Transparent"/>             <Setter Property="BorderBrush" Value="Transparent"/>         </Style>     </Window.Styles>     <Design.DataContext>         <vm:MainWindowViewModel/>     </Design.DataContext>           <StackPanel>         <StackPanel Opacity="0.1" Height="38" Width="471">         </StackPanel>         <Border Name="Border" Width="471" CornerRadius="10" Opacity="1" Background="#FFFFFF">             <Button>按钮</Button>            </Border>     </StackPanel> </Window>
以下代码在上面窗口用于设置窗口无边框
 
1 2 3 4 5 6 7 8 <Window.Styles>         <Style Selector="Window">             <Setter Property="BorderThickness" Value="0"/>             <Setter Property="Padding" Value="0"/>             <Setter Property="Background" Value="Transparent"/>             <Setter Property="BorderBrush" Value="Transparent"/>         </Style>     </Window.Styles>
然后打开/Views/MainWindow.axaml.cs文件,将边框设置成无边框,并且设置窗体透明为WindowTransparencyLevel.Transparent
 
1 2 3 4 5 6 7 8 9 10 11 12 13 using Avalonia; using Avalonia.Controls; namespace DragDemo.Views; public partial class MainWindow : Window {     public MainWindow()     {         InitializeComponent();         this.TransparencyLevelHint = WindowTransparencyLevel.Transparent;         ExtendClientAreaToDecorationsHint = true;         WindowState = WindowState.Maximized;     } }
效果图如下,因为限制了窗体最大大小,并且在按钮上面添加了透明区块,这样看起来就像是悬浮了
然后我们开始写指定组件拖动工具类,创建DragControlHelper.cs以下就是封装的工具类 定义了一个ConcurrentDictionary静态参数,指定组件为KeyValueDragModuleDragModule模型中定义了拖动的逻辑在调用StartDrag的时候传递需要拖动的组件,他会创建一个DragModule对象,创建的时候会创建定时器,当鼠标被按下时启动定时器,当鼠标被释放时定时器被停止,定时器用于平滑更新窗体移动,如果直接移动窗体会抖动。
 
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 using System; using System.Collections.Concurrent; using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Threading; using Avalonia.VisualTree; namespace DragDemo; public class DragControlHelper {     private static ConcurrentDictionary<Control, DragModule> _dragModules = new();     public static void StartDrag(Control userControl)     {         _dragModules.TryAdd(userControl, new DragModule(userControl));     }     public static void StopDrag(Control userControl)     {         if (_dragModules.TryRemove(userControl, out var dragModule))         {             dragModule.Dispose();         }     } } class DragModule : IDisposable {     /// <summary>     /// 记录上一次鼠标位置     /// </summary>     private Point? lastMousePosition;     /// <summary>     /// 用于平滑更新坐标的计时器     /// </summary>     private DispatcherTimer _timer;     /// <summary>     /// 标记是否先启动了拖动     /// </summary>     private bool isDragging = false;     /// <summary>     /// 需要更新的坐标点     /// </summary>     private PixelPoint? _targetPosition;     public Control UserControl { get; set; }     public DragModule(Control userControl)     {         UserControl = userControl;         // 添加当前控件的事件监听         UserControl.PointerPressed += OnPointerPressed;         UserControl.PointerMoved += OnPointerMoved;         UserControl.PointerReleased += OnPointerReleased;         // 初始化计时器         _timer = new DispatcherTimer         {             Interval = TimeSpan.FromMilliseconds(10)         };         _timer.Tick += OnTimerTick;     }     /// <summary>     /// 计时器事件     /// </summary>     /// <param name="sender"></param>     /// <param name="e"></param>     private void OnTimerTick(object sender, EventArgs e)     {         var window = UserControl.FindAncestorOfType<Window>();         if (window != null && window.Position != _targetPosition)         {             // 更新坐标             window.Position = (PixelPoint)_targetPosition;         }     }     private void OnPointerPressed(object sender, PointerPressedEventArgs e)     {         if (!e.GetCurrentPoint(UserControl).Properties.IsLeftButtonPressed) return;         // 启动拖动         isDragging = true;         // 记录当前坐标         lastMousePosition = e.GetPosition(UserControl);         e.Handled = true;         // 启动计时器         _timer.Start();     }     private void OnPointerReleased(object sender, PointerReleasedEventArgs e)     {         if (!isDragging) return;         // 停止拖动         isDragging = false;         e.Handled = true;         // 停止计时器         _timer.Stop();     }     private void OnPointerMoved(object sender, PointerEventArgs e)     {         if (!e.GetCurrentPoint(UserControl).Properties.IsLeftButtonPressed) return;         // 如果没有启动拖动,则不执行         if (!isDragging) return;         var currentMousePosition = e.GetPosition(UserControl);         var offset =currentMousePosition - lastMousePosition.Value;         var window = UserControl.FindAncestorOfType<Window>();         if (window != null)         {             // 记录当前坐标             _targetPosition = new PixelPoint(window.Position.X + (int)offset.X,                 window.Position.Y + (int)offset.Y);         }     }     public void Dispose()     {         _timer.Stop();         _targetPosition = null;         lastMousePosition = null;     } }
打开MainWindow.axaml.cs,修改成以下代码 ,在渲染成功以后拿到Border(需要移动的组件),添加到DragControlHelper.StartDrag(border);中,然后再OnUnloaded的时候将Border再卸载掉
 
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 using Avalonia; using Avalonia.Controls; using Avalonia.Media; using Avalonia.Threading; namespace DragDemo.Views; public partial class MainWindow : Window {     public MainWindow()     {         InitializeComponent();         this.TransparencyLevelHint = WindowTransparencyLevel.Transparent;         ExtendClientAreaToDecorationsHint = true;         WindowState = WindowState.Maximized;     }     public override void Render(DrawingContext context)     {         base.Render(context);         Dispatcher.UIThread.Post(() =>         {             var border = this.Find<Border>("Border");             DragControlHelper.StartDrag(border);         });     }     protected override void OnUnloaded()     {         var border = this.Find<Border>("Border");         DragControlHelper.StopDrag(border);         base.OnUnloaded();     } }

效果展示:

到此这篇关于Avalonia封装实现指定组件允许拖动的工具类的文章就介绍到这了,更多相关Avalonia拖动指定组件内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

 

抄来的:https://www.inte.net/news/275386.html

标签:封装,拖动,UserControl,using,Avalonia,public,DragDemo
From: https://www.cnblogs.com/ZhyjEye/p/18531754

相关文章

  • 类的三大特性(封装、继承、多态)
    1.封装:封装是指将数据(属性)和行为(方法)捆绑在一起,形成一个对象,并通过公共接口来访问这个对象。封装的目的是保护对象的内部状态,防止外部直接访问和修改对象的数据,确保数据的完整性和程序的安全性。封装的意义:1.将属性和行为作为一个整体,表现在生活中的事物2.将属性和行为加以......
  • Python 继承、多态、封装、抽象
    面向对象编程(OOP)是Python中的一种重要编程范式,它通过类和对象来组织代码。OOP的四个核心概念是继承(Inheritance)、多态(Polymorphism)、封装(Encapsulation)和数据抽象(DataAbstraction)。下面将详细介绍这四个概念。继承(Inheritance)继承是面向对象编程(OOP)的一个基本概念,它允......
  • C语言字符数组 java封装
    1.intmain(void){   inta[5]={1,3,5,7,9};   charstrl[5]={'A','B','C','D','E'};   charstr2[5]="ABCD";//不能是ABCDE,最后还有\0   inti=0;   //for(i=0;i<5;i++)   //{ ......
  • Avalonia开源控件库强力推荐-Semi.Avalonia
    Avalonia是什么?Avalonia是一个强大的框架,使开发人员能够使用.NET创建跨平台应用程序。它使用自己的渲染引擎绘制UI控件,确保在Windows、macOS、Linux、Android、iOS和WebAssembly等不同平台上具有一致的外观和行为。这意味着开发人员可以共享他们的UI代码,并在不同的目标平台上保持......
  • 0基础学Python装饰器封装、类成员与静态方法、魔术方法
    0基础学Python装饰器封装、类成员与静态方法、魔术方法装饰器封装类成员和静态方法实例属性和方法类属性和类方法静态方法使用场景魔术方法定义初始化与表示方法比较运算方法算术运算方法代码演示装饰器封装装饰器(decorators)是一种高阶函数,用于在不修改原有函数或......
  • 使用wxpython开发跨平台桌面应用,基类对话框窗体的封装处理
    在开发桌面界面的时候,往往都需要对一些通用的窗体进行一些抽象封装处理,以便统一界面效果,以及继承一些通用的处理过程,减少重复编码。本篇随笔介绍使用wxpython开发跨平台桌面应用,基类对话框窗体的封装处理,介绍基于wx.lib.sized_controls.SizedDialog对话框类的基类封装,以便简化子......
  • 封装红黑树实现mymap和myset
    前面我们已经了解过红黑树如何实现,和map与set的基本用法;要继续深入了解map,set中的库函数的用法,与细节那么我们就可以试着简单用语言封装模拟实现一下map与set; 这里就分享一下我的思路;若没了解过红黑树如何实现,和map与set的基本用法建议先去了解一下哦;我之前的文章中就有。......
  • 手机电脑端可拖动音乐播放器
    提示:播放器部分代码未美化,有需要请自行编写电脑端效果展示手机端效果展示CSS: #musicPlayer{position:fixed;width:300px;height:150px;bottom:20px;right:20px;padding:20px;background-color:#444;color:#......
  • 项目部署重要部分,axios二次封装,API接口统一管理
    5.10axios二次封装目的:1:使用请求拦截器,可以在请求拦截器中处理一些业务(开始进度条、请求头携带公共参数)2:使用响应拦截器,可以在响应拦截器中处理一些业务(进度条结束、简化服务器返回的数据、处理http网络错误)在项目中安装axiospnpmiaxios在src文件下新建util......
  • Geogebra基础篇019—Geogebra的移动工具(单选、框选、沿点线面体拖动、自由旋转、指定
    注意:关注微信公众号“第五智能”,免费查阅全系列文章(或者微信顶部直接搜索“Geogebra的移动工具”就可以找到了)。关于Geogebra移动工具的知识还是比较繁琐的,比如视图中的对象,大家都知道点击单选,但是怎么框选呢?怎么横移画布、怎么沿点拖动、沿线拖动、沿面拖动、甚至是沿体积......