GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!
 【 如果你想靠AI翻身,你先需要一个靠谱的工具! 】
创建Avalonia的MVVM项目,命名DragDemo ,然后将项目的Nuget包更新到预览版
| 1 2 3 4 5 6 7 8 | <ItemGroup>    <PackageReferenceInclude="Avalonia"Version="11.0.0-preview5"/>    <PackageReferenceInclude="Avalonia.Desktop"Version="11.0.0-preview5"/>    <!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->    <PackageReferenceCondition="'$(Configuration)' == 'Debug'"Include="Avalonia.Diagnostics"Version="11.0.0-preview5"/>    <PackageReferenceInclude="Avalonia.ReactiveUI"Version="11.0.0-preview5"/>    <PackageReferenceInclude="XamlNameReferenceGenerator"Version="1.5.1"/></ItemGroup> | 
更新完成以后ViewLocator和App.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 28 29 30 31 32 | usingSystem;usingAvalonia.Controls;usingAvalonia.Controls.Templates;usingDragDemo.ViewModels;namespaceDragDemo;publicclassViewLocator : IDataTemplate{    /// <summary>    /// 将IControl修改成Control    /// </summary>    /// <param name="data"></param>    /// <returns></returns>    publicControl Build(objectdata)    {        var name = data.GetType().FullName!.Replace("ViewModel", "View");        var type = Type.GetType(name);        if(type != null)        {            return(Control)Activator.CreateInstance(type)!;        }        returnnewTextBlock { Text = "Not Found: "+ name };    }    publicboolMatch(objectdata)    {        returndata isViewModelBase;    }} | 
添加Avalonia.Themes.Fluent,因为预览版本的包已经独立需要单独安装
| 1 | <PackageReferenceInclude="Avalonia.Themes.Fluent"Version="11.0.0-preview5"/> | 
打开App.axaml文件,修改为以下代码
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <Applicationxmlns="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>        <FluentThemeDensityStyle="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 | <Windowxmlns="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>        <StyleSelector="Window">            <SetterProperty="BorderThickness"Value="0"/>            <SetterProperty="Padding"Value="0"/>            <SetterProperty="Background"Value="Transparent"/>            <SetterProperty="BorderBrush"Value="Transparent"/>        </Style>    </Window.Styles>    <Design.DataContext>        <vm:MainWindowViewModel/>    </Design.DataContext>        <StackPanel>        <StackPanelOpacity="0.1"Height="38"Width="471">        </StackPanel>        <BorderName="Border"Width="471"CornerRadius="10"Opacity="1"Background="#FFFFFF">            <Button>按钮</Button>            </Border>    </StackPanel></Window> | 
以下代码在上面窗口用于设置窗口无边框
| 1 2 3 4 5 6 7 8 | <Window.Styles>    <StyleSelector="Window">        <SetterProperty="BorderThickness"Value="0"/>        <SetterProperty="Padding"Value="0"/>        <SetterProperty="Background"Value="Transparent"/>        <SetterProperty="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 14 15 | usingAvalonia;usingAvalonia.Controls;namespaceDragDemo.Views;publicpartialclassMainWindow : Window{    publicMainWindow()    {        InitializeComponent();        this.TransparencyLevelHint = WindowTransparencyLevel.Transparent;        ExtendClientAreaToDecorationsHint = true;        WindowState = WindowState.Maximized;    }} | 
效果图如下,因为限制了窗体最大大小,并且在按钮上面添加了透明区块,这样看起来就像是悬浮了
然后我们开始写指定组件拖动工具类,创建DragControlHelper.cs 以下就是封装的工具类 定义了一个ConcurrentDictionary静态参数,指定组件为Key ,Value为DragModule ,DragModule模型中定义了拖动的逻辑在调用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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | usingSystem;usingSystem.Collections.Concurrent;usingAvalonia;usingAvalonia.Controls;usingAvalonia.Input;usingAvalonia.Threading;usingAvalonia.VisualTree;namespaceDragDemo;publicclassDragControlHelper{    privatestaticConcurrentDictionary<Control, DragModule> _dragModules = new();    publicstaticvoidStartDrag(Control userControl)    {        _dragModules.TryAdd(userControl, newDragModule(userControl));    }    publicstaticvoidStopDrag(Control userControl)    {        if(_dragModules.TryRemove(userControl, outvar dragModule))        {            dragModule.Dispose();        }    }}classDragModule : IDisposable{    /// <summary>    /// 记录上一次鼠标位置    /// </summary>    privatePoint? lastMousePosition;    /// <summary>    /// 用于平滑更新坐标的计时器    /// </summary>    privateDispatcherTimer _timer;    /// <summary>    /// 标记是否先启动了拖动    /// </summary>    privateboolisDragging = false;    /// <summary>    /// 需要更新的坐标点    /// </summary>    privatePixelPoint? _targetPosition;    publicControl UserControl { get; set; }    publicDragModule(Control userControl)    {        UserControl = userControl;        // 添加当前控件的事件监听        UserControl.PointerPressed += OnPointerPressed;        UserControl.PointerMoved += OnPointerMoved;        UserControl.PointerReleased += OnPointerReleased;        // 初始化计时器        _timer = newDispatcherTimer        {            Interval = TimeSpan.FromMilliseconds(10)        };        _timer.Tick += OnTimerTick;    }    /// <summary>    /// 计时器事件    /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    privatevoidOnTimerTick(objectsender, EventArgs e)    {        var window = UserControl.FindAncestorOfType<Window>();        if(window != null&& window.Position != _targetPosition)        {            // 更新坐标            window.Position = (PixelPoint)_targetPosition;        }    }    privatevoidOnPointerPressed(objectsender, PointerPressedEventArgs e)    {        if(!e.GetCurrentPoint(UserControl).Properties.IsLeftButtonPressed) return;        // 启动拖动        isDragging = true;        // 记录当前坐标        lastMousePosition = e.GetPosition(UserControl);        e.Handled = true;        // 启动计时器        _timer.Start();    }    privatevoidOnPointerReleased(objectsender, PointerReleasedEventArgs e)    {        if(!isDragging) return;        // 停止拖动        isDragging = false;        e.Handled = true;        // 停止计时器        _timer.Stop();    }    privatevoidOnPointerMoved(objectsender, 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 = newPixelPoint(window.Position.X + (int)offset.X,                window.Position.Y + (int)offset.Y);        }    }    publicvoidDispose()    {        _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 31 32 33 34 | usingAvalonia;usingAvalonia.Controls;usingAvalonia.Media;usingAvalonia.Threading;namespaceDragDemo.Views;publicpartialclassMainWindow : Window{    publicMainWindow()    {        InitializeComponent();        this.TransparencyLevelHint = WindowTransparencyLevel.Transparent;        ExtendClientAreaToDecorationsHint = true;        WindowState = WindowState.Maximized;    }    publicoverridevoidRender(DrawingContext context)    {        base.Render(context);        Dispatcher.UIThread.Post(() =>        {            var border = this.Find<Border>("Border");            DragControlHelper.StartDrag(border);        });    }    protectedoverridevoidOnUnloaded()    {        var border = this.Find<Border>("Border");        DragControlHelper.StopDrag(border);        base.OnUnloaded();    }} | 
效果展示:

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