Avalonia封装实现指定组件允许拖动的工具类
创建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 > |
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
|
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
|
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
|
xmlns:vm = "using:DragDemo.ViewModels" 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
静态参数,指定组件为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
|
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