标签:封装 拖动 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" />
< 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
|
< 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
静态参数,指定组件为
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
标签:封装,
拖动,
UserControl,
using,
Avalonia,
public,
DragDemo
From: https://www.cnblogs.com/ZhyjEye/p/18531754