Avalonia封裝實(shí)現(xiàn)指定組件允許拖動的工具類
創(chuàng)建Avalonia
的MVVM項(xiàng)目,命名DragDemo
,然后將項(xiàng)目的Nuget包更新到預(yù)覽版
<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
會報(bào)錯,
修改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
,因?yàn)轭A(yù)覽版本的包已經(jīng)獨(dú)立需要單獨(dú)安裝
<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
在頭部添加以下代碼,讓窗口無邊框,設(shè)置指定窗口Height="38" Width="471",參數(shù)讓其不要占用整個屏幕,
<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>
以下代碼在上面窗口用于設(shè)置窗口無邊框
<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
文件,將邊框設(shè)置成無邊框,并且設(shè)置窗體透明為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; } }
效果圖如下,因?yàn)橄拗屏舜绑w最大大小,并且在按鈕上面添加了透明區(qū)塊,這樣看起來就像是懸浮了
然后我們開始寫指定組件拖動工具類,創(chuàng)建DragControlHelper.cs
以下就是封裝的工具類 定義了一個ConcurrentDictionary
靜態(tài)參數(shù),指定組件為Key
,Value
為DragModule
,DragModule
模型中定義了拖動的邏輯在調(diào)用StartDrag
的時候傳遞需要拖動的組件,他會創(chuàng)建一個DragModule
對象,創(chuàng)建的時候會創(chuàng)建定時器,當(dāng)鼠標(biāo)被按下時啟動定時器,當(dāng)鼠標(biāo)被釋放時定時器被停止,定時器用于平滑更新窗體移動,如果直接移動窗體會抖動。
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> /// 記錄上一次鼠標(biāo)位置 /// </summary> private Point? lastMousePosition; /// <summary> /// 用于平滑更新坐標(biāo)的計(jì)時器 /// </summary> private DispatcherTimer _timer; /// <summary> /// 標(biāo)記是否先啟動了拖動 /// </summary> private bool isDragging = false; /// <summary> /// 需要更新的坐標(biāo)點(diǎn) /// </summary> private PixelPoint? _targetPosition; public Control UserControl { get; set; } public DragModule(Control userControl) { UserControl = userControl; // 添加當(dāng)前控件的事件監(jiān)聽 UserControl.PointerPressed += OnPointerPressed; UserControl.PointerMoved += OnPointerMoved; UserControl.PointerReleased += OnPointerReleased; // 初始化計(jì)時器 _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(10) }; _timer.Tick += OnTimerTick; } /// <summary> /// 計(jì)時器事件 /// </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) { // 更新坐標(biāo) window.Position = (PixelPoint)_targetPosition; } } private void OnPointerPressed(object sender, PointerPressedEventArgs e) { if (!e.GetCurrentPoint(UserControl).Properties.IsLeftButtonPressed) return; // 啟動拖動 isDragging = true; // 記錄當(dāng)前坐標(biāo) lastMousePosition = e.GetPosition(UserControl); e.Handled = true; // 啟動計(jì)時器 _timer.Start(); } private void OnPointerReleased(object sender, PointerReleasedEventArgs e) { if (!isDragging) return; // 停止拖動 isDragging = false; e.Handled = true; // 停止計(jì)時器 _timer.Stop(); } private void OnPointerMoved(object sender, PointerEventArgs e) { if (!e.GetCurrentPoint(UserControl).Properties.IsLeftButtonPressed) return; // 如果沒有啟動拖動,則不執(zhí)行 if (!isDragging) return; var currentMousePosition = e.GetPosition(UserControl); var offset =currentMousePosition - lastMousePosition.Value; var window = UserControl.FindAncestorOfType<Window>(); if (window != null) { // 記錄當(dāng)前坐標(biāo) _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
的時候?qū)?code>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(); } }
效果展示:
到此這篇關(guān)于Avalonia封裝實(shí)現(xiàn)指定組件允許拖動的工具類的文章就介紹到這了,更多相關(guān)Avalonia拖動指定組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Unity中RectTransform與transform的區(qū)別
這篇文章主要介紹了Unity中RectTransform與transform的區(qū)別,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-01-01C#使用Microsoft消息隊(duì)列(MSMQ)的示例詳解
Microsoft?Message?Queuing?(MSMQ)?是在多個不同的應(yīng)用之間實(shí)現(xiàn)相互通信的一種異步傳輸模式,本文主要介紹了C#如何使用Microsoft消息隊(duì)列,需要的可以了解下2024-01-01js驗(yàn)證電話號碼手機(jī)號碼的正則表達(dá)式
本篇文章主要是對js驗(yàn)證電話號碼手機(jī)號碼的正則表達(dá)式進(jìn)行了介紹。需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01C#簡易圖片格式轉(zhuǎn)換器實(shí)現(xiàn)方法
這篇文章主要介紹了C#簡易圖片格式轉(zhuǎn)換器實(shí)現(xiàn)方法,涉及C#基于WinForm操作圖片的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11