文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-07-05 07:08

关注

今天小编给大家分享一下Avalonia如何封装实现指定组件允许拖动的工具类的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

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

    <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为下面的代码

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,因为预览版本的包已经独立需要单独安装

<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0-preview5" />

打开App.axaml文件,修改为以下代码

<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",参数让其不要占用整个屏幕,

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

以下代码在上面窗口用于设置窗口无边框

    <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

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静态参数,指定组件为Key ,ValueDragModule ,DragModule模型中定义了拖动的逻辑在调用StartDrag的时候传递需要拖动的组件,他会创建一个DragModule对象,创建的时候会创建定时器,当鼠标被按下时启动定时器,当鼠标被释放时定时器被停止,定时器用于平滑更新窗体移动,如果直接移动窗体会抖动。

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再卸载掉

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如何封装实现指定组件允许拖动的工具类”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯