Add ProDataGrid (#10347)

* Bump Avalonia.Desktop from 12.1.2 to 12.1.4

---
updated-dependencies:
- dependency-name: Avalonia.Desktop
  dependency-version: 12.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Remove Avalonia.Controls.DataGrid

* Add ProDataGrid Feature

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
This commit is contained in:
DHR60
2026-11-01 12:34:24 +00:00
committed by GitHub
parent 78b0b2224b
commit 8b93d35766
14 changed files with 393 additions and 184 deletions
+2 -3
View File
@@ -6,8 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia.AvaloniaEdit" Version="12.0.0" />
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="12.1.2" />
<PackageVersion Include="Avalonia.Desktop" Version="12.1.2" />
<PackageVersion Include="Avalonia.Desktop" Version="12.1.4" />
<PackageVersion Include="AvaloniaUI.DiagnosticsSupport" Version="2.2.3" />
<PackageVersion Include="DialogHost.Avalonia" Version="0.12.3" />
<PackageVersion Include="IPNetwork2" Version="4.3.0" />
@@ -32,4 +31,4 @@
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.22" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="3.119.4" />
</ItemGroup>
</Project>
</Project>
@@ -540,6 +540,67 @@ public static class ConfigHandler
return await Task.FromResult(0);
}
public static Task<int> MoveServersTo(
Config config,
IReadOnlyList<string> orderedProfileIds,
IReadOnlyList<int> sourceIndices,
int insertIndex)
{
ArgumentNullException.ThrowIfNull(orderedProfileIds);
ArgumentNullException.ThrowIfNull(sourceIndices);
if (orderedProfileIds.Count == 0 ||
sourceIndices.Count == 0 ||
insertIndex < 0 ||
insertIndex > orderedProfileIds.Count)
{
return Task.FromResult(-1);
}
int[] movingIndices = sourceIndices
.Distinct()
.OrderBy(index => index)
.ToArray();
if (movingIndices.Length != sourceIndices.Count ||
movingIndices.Any(index =>
index < 0 || index >= orderedProfileIds.Count))
{
return Task.FromResult(-1);
}
var movingIndexSet = movingIndices.ToHashSet();
var movingIds = movingIndices
.Select(index => orderedProfileIds[index])
.ToList();
var remainingIds = orderedProfileIds
.Where((_, index) => !movingIndexSet.Contains(index))
.ToList();
if (insertIndex > remainingIds.Count)
{
return Task.FromResult(-1);
}
remainingIds.InsertRange(insertIndex, movingIds);
if (remainingIds.Count != orderedProfileIds.Count)
{
return Task.FromResult(-1);
}
for (var index = 0; index < remainingIds.Count; index++)
{
ProfileExManager.Instance.SetSort(
remainingIds[index],
(index + 1) * 10);
}
return Task.FromResult(0);
}
/// <summary>
/// Add a custom server configuration from a file
/// Copies the configuration file to the app's config directory
+9
View File
@@ -978,6 +978,15 @@ namespace ServiceLib.Resx {
}
}
/// <summary>
/// 查找类似 Columns 的本地化字符串。
/// </summary>
public static string menuColumns {
get {
return ResourceManager.GetString("menuColumns", resourceCulture);
}
}
/// <summary>
/// 查找类似 Close Connection 的本地化字符串。
/// </summary>
+3
View File
@@ -1905,4 +1905,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuAddMasqueServer" xml:space="preserve">
<value>Add [MASQUE]</value>
</data>
<data name="menuColumns" xml:space="preserve">
<value>Columns</value>
</data>
</root>
@@ -1897,4 +1897,7 @@
<data name="menuAddMasqueServer" xml:space="preserve">
<value>添加 [MASQUE]</value>
</data>
<data name="menuColumns" xml:space="preserve">
<value>列</value>
</data>
</root>
@@ -702,6 +702,33 @@ public partial class ProfilesViewModel : MyReactiveObject
}
}
public async Task MoveServersTo(
IReadOnlyList<int> sourceIndices,
int insertIndex)
{
if (sourceIndices.Count == 0 ||
insertIndex < 0 ||
insertIndex > ProfileItems.Count)
{
return;
}
var orderedProfileIds = ProfileItems
.Select(item => item.IndexId)
.ToList();
var result = await ConfigHandler.MoveServersTo(
_config,
orderedProfileIds,
sourceIndices,
insertIndex);
if (result == 0)
{
await RefreshServers();
}
}
public async Task ServerSpeedtest(ESpeedActionType actionType)
{
List<ProfileItem>? lstSelected;
+2 -1
View File
@@ -5,6 +5,7 @@
xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:semi="https://irihi.tech/semi"
xmlns:service="clr-namespace:ServiceLib;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Name="v2rayN"
x:DataType="vms:StatusBarViewModel"
@@ -37,7 +38,7 @@
<TrayIcon
Command="{Binding NotifyLeftClickCmd}"
Icon="/Assets/NotifyIcon1.ico"
ToolTipText="{Binding RunningServerToolTipText}">
ToolTipText="{Binding RunningServerToolTipText, FallbackValue={x:Static service:Global.AppName}}">
<TrayIcon.Menu>
<NativeMenu>
<NativeMenuItem
@@ -148,11 +148,13 @@
CanUserReorderColumns="False"
CanUserResizeColumns="True"
CanUserSortColumns="False"
FrozenColumnCount="2"
GridLinesVisibility="All"
HeadersVisibility="Column"
HeadersVisibility="All"
IsReadOnly="True"
ItemsSource="{Binding ChildItemsObs}"
SelectionMode="Extended">
SelectionMode="Extended"
ShowRowNumbers="True">
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuAddChildServer" Header="{x:Static resx:ResUI.menuAddChildServer}" />
@@ -220,11 +222,13 @@
CanUserReorderColumns="False"
CanUserResizeColumns="True"
CanUserSortColumns="False"
FrozenColumnCount="2"
GridLinesVisibility="All"
HeadersVisibility="Column"
HeadersVisibility="All"
IsReadOnly="True"
ItemsSource="{Binding AllProfilePreviewItemsObs}"
SelectionMode="Extended">
SelectionMode="Extended"
ShowRowNumbers="True">
<DataGrid.Columns>
<DataGridTextColumn
Width="150"
@@ -55,7 +55,6 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
// Keyboard shortcuts when focus is within grid
AddHandler(KeyDownEvent, AddGroupServerWindow_KeyDown, RoutingStrategies.Tunnel);
lstChild.LoadingRow += LstChild_LoadingRow;
}
private void InitializeData(ProfileItem profileItem)
@@ -77,11 +76,6 @@ public partial class AddGroupServerWindow : WindowBase<AddGroupServerViewModel>
}
}
private void LstChild_LoadingRow(object? sender, DataGridRowEventArgs e)
{
e.Row.Header = $" {e.Row.Index + 1}";
}
private void Window_Loaded(object? sender, RoutedEventArgs e)
{
txtRemarks.Focus();
@@ -71,8 +71,8 @@
Width="200"
Margin="{StaticResource MarginLr4}"
VerticalContentAlignment="Center"
Text="{Binding ServerFilter, Mode=TwoWay}"
PlaceholderText="{x:Static resx:ResUI.MsgServerTitle}"
Text="{Binding ServerFilter, Mode=TwoWay}"
ToolTip.Tip="{x:Static resx:ResUI.MsgServerTitle}" />
</WrapPanel>
@@ -83,11 +83,13 @@
BorderThickness="1"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
FrozenColumnCount="2"
GridLinesVisibility="All"
HeadersVisibility="All"
IsReadOnly="True"
ItemsSource="{Binding ProfileItems}"
SelectionMode="Single">
SelectionMode="Single"
ShowRowNumbers="True">
<DataGrid.KeyBindings>
<KeyBinding Command="{Binding SelectFinish}" Gesture="Enter" />
</DataGrid.KeyBindings>
@@ -14,7 +14,6 @@ public partial class ProfilesSelectWindow : WindowBase<ProfilesSelectViewModel>
txtServerFilter.KeyDown += TxtServerFilter_KeyDown;
lstProfiles.KeyDown += LstProfiles_KeyDown;
lstProfiles.SelectionChanged += LstProfiles_SelectionChanged;
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
lstProfiles.Sorting += LstProfiles_Sorting;
lstProfiles.DoubleTapped += LstProfiles_DoubleTapped;
@@ -61,11 +60,6 @@ public partial class ProfilesSelectWindow : WindowBase<ProfilesSelectViewModel>
}
}
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
{
e.Row.Header = $" {e.Row.Index + 1}";
}
private void LstProfiles_DoubleTapped(object? sender, TappedEventArgs e)
{
// Ignore double-taps on the column header area
+83 -14
View File
@@ -16,6 +16,48 @@
mc:Ignorable="d">
<UserControl.Resources>
<conv:DelayColorConverter x:Key="DelayColorConverter" />
<ControlTheme x:Key="{x:Type DataGridColumnChooser}" TargetType="DataGridColumnChooser">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate x:DataType="DataGridColumnChooserItem">
<CheckBox
Margin="0,2"
Content="{Binding Header}"
IsChecked="{Binding IsVisible, Mode=TwoWay}"
IsEnabled="{Binding CanUserHide}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Spacing="4" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Button Classes="IconButton Success" ToolTip.Tip="{TemplateBinding ToolTip.Tip}">
<Button.Flyout>
<Flyout Placement="BottomEdgeAlignedLeft">
<Border
MaxWidth="260"
MaxHeight="360"
Padding="8">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</Border>
</Flyout>
</Button.Flyout>
<ContentPresenter Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" />
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</ControlTheme>
</UserControl.Resources>
<Grid>
<DockPanel>
@@ -79,6 +121,15 @@
</Button.Content>
</Button>
<DataGridColumnChooser
Margin="{StaticResource MarginLr4}"
DataGrid="{Binding ElementName=lstProfiles}"
ToolTip.Tip="{x:Static resx:ResUI.menuColumns}">
<DataGridColumnChooser.Header>
<PathIcon Data="{StaticResource SemiIconSetting}" />
</DataGridColumnChooser.Header>
</DataGridColumnChooser>
<Button
x:Name="btnFastRealPing"
Margin="{StaticResource MarginLr4}"
@@ -97,20 +148,27 @@
<PathIcon Data="{StaticResource building_ping}" />
</Button.Content>
</Button>
</StackPanel>
</WrapPanel>
<DataGrid
x:Name="lstProfiles"
AutoGenerateColumns="False"
BorderThickness="1"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserHideColumns="True"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
Classes.InsetContent="True"
FrozenColumnCount="2"
GridLinesVisibility="All"
HeadersVisibility="All"
IsReadOnly="True"
ItemsSource="{Binding ProfileItems}">
IsReadOnly="False"
ItemsSource="{Binding ProfileItems}"
ShowRowNumbers="True">
<DataGrid.KeyBindings>
<KeyBinding Command="{Binding Export2ShareUrlCmd}" Gesture="Ctrl+C" />
<KeyBinding Command="{Binding SetDefaultServerCmd}" Gesture="Enter" />
@@ -212,12 +270,13 @@
Width="80"
Binding="{Binding ConfigType}"
Header="{x:Static resx:ResUI.LvServiceType}"
IsReadOnly="True"
Tag="ConfigType" />
<DataGridTemplateColumn SortMemberPath="Remarks" Tag="Remarks">
<DataGridTemplateColumn.Header>
<TextBlock Text="{x:Static resx:ResUI.LvRemarks}" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn
Header="{x:Static resx:ResUI.LvRemarks}"
SortMemberPath="Remarks"
Tag="Remarks">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Margin="{StaticResource MarginLr8}" Orientation="Horizontal">
@@ -240,31 +299,36 @@
Width="120"
Binding="{Binding Address}"
Header="{x:Static resx:ResUI.LvAddress}"
IsReadOnly="True"
Tag="Address" />
<DataGridTextColumn
Width="60"
Binding="{Binding Port}"
Header="{x:Static resx:ResUI.LvPort}"
IsReadOnly="True"
Tag="Port" />
<DataGridTextColumn
Width="100"
Binding="{Binding Network}"
Header="{x:Static resx:ResUI.LvTransportProtocol}"
IsReadOnly="True"
Tag="Network" />
<DataGridTextColumn
Width="100"
Binding="{Binding StreamSecurity}"
Header="{x:Static resx:ResUI.LvTLS}"
IsReadOnly="True"
Tag="StreamSecurity" />
<DataGridTextColumn
Width="100"
Binding="{Binding SubRemarks}"
Header="{x:Static resx:ResUI.LvSubscription}"
IsReadOnly="True"
Tag="SubRemarks" />
<DataGridTemplateColumn SortMemberPath="Delay" Tag="DelayVal">
<DataGridTemplateColumn.Header>
<TextBlock Text="{x:Static resx:ResUI.LvTestDelay}" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn
Header="{x:Static resx:ResUI.LvTestDelay}"
SortMemberPath="Delay"
Tag="DelayVal">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock
@@ -280,12 +344,13 @@
Width="100"
Binding="{Binding SpeedVal}"
Header="{x:Static resx:ResUI.LvTestSpeed}"
IsReadOnly="True"
Tag="SpeedVal" />
<DataGridTemplateColumn SortMemberPath="IpInfo" Tag="IpInfo">
<DataGridTemplateColumn.Header>
<TextBlock Text="{x:Static resx:ResUI.LvTestIpInfo}" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn
Header="{x:Static resx:ResUI.LvTestIpInfo}"
SortMemberPath="IpInfo"
Tag="IpInfo">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<SelectableTextBlock
@@ -300,21 +365,25 @@
Width="100"
Binding="{Binding TodayUp}"
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}"
IsReadOnly="True"
Tag="TodayUp" />
<DataGridTextColumn
Width="100"
Binding="{Binding TodayDown}"
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}"
IsReadOnly="True"
Tag="TodayDown" />
<DataGridTextColumn
Width="100"
Binding="{Binding TotalUp}"
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}"
IsReadOnly="True"
Tag="TotalUp" />
<DataGridTextColumn
Width="100"
Binding="{Binding TotalDown}"
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}"
IsReadOnly="True"
Tag="TotalDown" />
</DataGrid.Columns>
</DataGrid>
+190 -145
View File
@@ -1,4 +1,4 @@
using Avalonia.VisualTree;
using Avalonia.Controls.DataGridDragDrop;
using DialogHostAvalonia;
using v2rayN.Desktop.Common;
@@ -8,6 +8,7 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
{
private static Config _config;
private static readonly string _tag = "ProfilesView";
private bool _isDndRegistered = false;
public ProfilesView()
{
@@ -21,18 +22,17 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
lstProfiles.KeyDown += LstProfiles_KeyDown;
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
lstProfiles.DoubleTapped += LstProfiles_DoubleTapped;
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
lstProfiles.Sorting += LstProfiles_Sorting;
if (_config.UiItem.EnableDragDropSort)
{
lstProfiles.SetValue(DragDrop.AllowDropProperty, true);
//if (_config.UiItem.EnableDragDropSort)
//{
// lstProfiles.SetValue(DragDrop.AllowDropProperty, true);
lstProfiles.AddHandler(PointerPressedEvent, LstProfiles_PointerPressed, RoutingStrategies.Bubble, true);
lstProfiles.AddHandler(PointerMovedEvent, LstProfiles_PointerMoved, RoutingStrategies.Bubble, true);
lstProfiles.AddHandler(PointerReleasedEvent, LstProfiles_PointerReleased, RoutingStrategies.Bubble, true);
lstProfiles.AddHandler(DragDrop.DragOverEvent, LstProfiles_DragOver, RoutingStrategies.Bubble);
lstProfiles.AddHandler(DragDrop.DropEvent, LstProfiles_Drop, RoutingStrategies.Bubble);
}
// lstProfiles.AddHandler(PointerPressedEvent, LstProfiles_PointerPressed, RoutingStrategies.Bubble, true);
// lstProfiles.AddHandler(PointerMovedEvent, LstProfiles_PointerMoved, RoutingStrategies.Bubble, true);
// lstProfiles.AddHandler(PointerReleasedEvent, LstProfiles_PointerReleased, RoutingStrategies.Bubble, true);
// lstProfiles.AddHandler(DragDrop.DragOverEvent, LstProfiles_DragOver, RoutingStrategies.Bubble);
// lstProfiles.AddHandler(DragDrop.DropEvent, LstProfiles_Drop, RoutingStrategies.Bubble);
//}
this.WhenActivated(disposables =>
{
@@ -84,6 +84,22 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
this.BindCommand(ViewModel, vm => vm.Export2ShareUrlBase64Cmd, v => v.menuExport2ShareUrlBase64).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.Export2InnerUriCmd, v => v.menuExport2InnerUri).DisposeWith(disposables);
if (_config.UiItem.EnableDragDropSort && !_isDndRegistered)
{
lstProfiles.CanUserReorderRows = true;
lstProfiles.RowDragHandle = DataGridRowDragHandle.RowHeaderAndRow;
lstProfiles.RowDragHandleVisible = true;
var rowDragDropOptions = new DataGridRowDragDropOptions()
{
AllowedEffects = DragDropEffects.Move,
DragSelectedRows = true,
SuppressSelectionDragFromDragHandle = true,
};
lstProfiles.RowDragDropOptions = rowDragDropOptions;
lstProfiles.RowDropHandler = new ProfileRowDropHandler(ViewModel);
_isDndRegistered = true;
}
ViewModel.ShowYesNoInteraction.RegisterHandler(async interaction =>
{
var message = interaction.Input;
@@ -216,11 +232,6 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
}
}
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
{
e.Row.Header = $" {e.Row.Index + 1}";
}
//private void LstProfiles_ColumnHeader_Click(object? sender, RoutedEventArgs e)
//{
// var colHeader = sender as DataGridColumnHeader;
@@ -435,140 +446,174 @@ public partial class ProfilesView : ReactiveUserControl<ProfilesViewModel>
#endregion UI
#region Drag and Drop
//#region Drag and Drop
private static readonly DataFormat<ProfileItemModel> LstProfilesRowFormat =
DataFormat.CreateInProcessFormat<ProfileItemModel>("LstProfilesRow");
//private static readonly DataFormat<ProfileItemModel> LstProfilesRowFormat =
// DataFormat.CreateInProcessFormat<ProfileItemModel>("LstProfilesRow");
private (Point, PointerPressedEventArgs)? _dragStartPoint;
//private (Point, PointerPressedEventArgs)? _dragStartPoint;
private void LstProfiles_PointerPressed(object? sender, PointerPressedEventArgs e)
//private void LstProfiles_PointerPressed(object? sender, PointerPressedEventArgs e)
//{
// var properties = e.GetCurrentPoint(this).Properties;
// if (properties.IsLeftButtonPressed)
// {
// _dragStartPoint = (e.GetPosition(this), e);
// }
//}
//private async void LstProfiles_PointerMoved(object? sender, PointerEventArgs e)
//{
// try
// {
// if (_dragStartPoint == null)
// {
// return;
// }
// var properties = e.GetCurrentPoint(this).Properties;
// if (!properties.IsLeftButtonPressed)
// {
// _dragStartPoint = null;
// return;
// }
// var currentPoint = e.GetPosition(this);
// var startPoint = _dragStartPoint.Value.Item1;
// var delta = startPoint - currentPoint;
// var threshold = new Vector(4, 4);
// if (!(Math.Abs(delta.X) >= threshold.X) && !(Math.Abs(delta.Y) >= threshold.Y))
// {
// return;
// }
// var dragStartEventArgs = _dragStartPoint.Value.Item2;
// _dragStartPoint = null;
// if (e.Source is not Visual visualSource)
// {
// return;
// }
// var row = visualSource.FindAncestorOfType<DataGridRow>(true);
// if (row?.DataContext == null)
// {
// return;
// }
// e.Handled = true;
// var dragData = new DataTransfer();
// var item = DataTransferItem.Create(LstProfilesRowFormat, row.DataContext as ProfileItemModel);
// dragData.Add(item);
// await DragDrop.DoDragDropAsync(dragStartEventArgs, dragData, DragDropEffects.Move);
// }
// catch
// {
// // Ignore
// }
//}
//private void LstProfiles_PointerReleased(object? sender, PointerReleasedEventArgs e)
//{
// _dragStartPoint = null;
//}
//private void LstProfiles_DragOver(object? sender, DragEventArgs e)
//{
// if (!e.DataTransfer.Contains(LstProfilesRowFormat))
// {
// e.DragEffects = DragDropEffects.None;
// return;
// }
// e.DragEffects = DragDropEffects.Move;
//}
//private void LstProfiles_Drop(object? sender, DragEventArgs e)
//{
// if (!e.DataTransfer.Contains(LstProfilesRowFormat))
// {
// return;
// }
// ProfileItemModel? sourceItem = null;
// foreach (var item in e.DataTransfer.Items)
// {
// if (!item.Formats.Contains(LstProfilesRowFormat))
// {
// continue;
// }
// if (item.TryGetRaw(LstProfilesRowFormat) is not ProfileItemModel model)
// {
// continue;
// }
// sourceItem = model;
// break;
// }
// if (sourceItem == null)
// {
// return;
// }
// if (e.Source is not Visual visualTarget)
// {
// return;
// }
// var targetRow = visualTarget.FindAncestorOfType<DataGridRow>(true);
// if (targetRow is not { DataContext: ProfileItemModel targetItem })
// {
// return;
// }
// if (ReferenceEquals(sourceItem, targetItem))
// {
// return;
// }
// if (lstProfiles.ItemsSource is not IList<ProfileItemModel> items)
// {
// return;
// }
// var oldIndex = items.IndexOf(sourceItem);
// var newIndex = items.IndexOf(targetItem);
// if (oldIndex >= 0 && newIndex >= 0)
// {
// ViewModel?.MoveServerTo(oldIndex, targetItem);
// }
//}
//#endregion Drag and Drop
private sealed class ProfileRowDropHandler(ProfilesViewModel viewModel) : IDataGridRowDropHandler
{
var properties = e.GetCurrentPoint(this).Properties;
if (properties.IsLeftButtonPressed)
private readonly DataGridRowReorderHandler _reorderHandler = new();
public bool Validate(DataGridRowDropEventArgs args)
{
_dragStartPoint = (e.GetPosition(this), e);
ArgumentNullException.ThrowIfNull(args);
return _reorderHandler.Validate(args);
}
public bool Execute(DataGridRowDropEventArgs args)
{
ArgumentNullException.ThrowIfNull(args);
if (!_reorderHandler.Execute(args))
{
return false;
}
if (viewModel?.ProfileItems != null)
{
for (var index = 0; index < viewModel.ProfileItems.Count; index++)
{
var item = viewModel.ProfileItems[index];
var sort = (index + 1) * 10;
item.Sort = sort;
ProfileExManager.Instance.SetSort(item.IndexId, sort);
}
}
return true;
}
}
private async void LstProfiles_PointerMoved(object? sender, PointerEventArgs e)
{
try
{
if (_dragStartPoint == null)
{
return;
}
var properties = e.GetCurrentPoint(this).Properties;
if (!properties.IsLeftButtonPressed)
{
_dragStartPoint = null;
return;
}
var currentPoint = e.GetPosition(this);
var startPoint = _dragStartPoint.Value.Item1;
var delta = startPoint - currentPoint;
var threshold = new Vector(4, 4);
if (!(Math.Abs(delta.X) >= threshold.X) && !(Math.Abs(delta.Y) >= threshold.Y))
{
return;
}
var dragStartEventArgs = _dragStartPoint.Value.Item2;
_dragStartPoint = null;
if (e.Source is not Visual visualSource)
{
return;
}
var row = visualSource.FindAncestorOfType<DataGridRow>(true);
if (row?.DataContext == null)
{
return;
}
e.Handled = true;
var dragData = new DataTransfer();
var item = DataTransferItem.Create(LstProfilesRowFormat, row.DataContext as ProfileItemModel);
dragData.Add(item);
await DragDrop.DoDragDropAsync(dragStartEventArgs, dragData, DragDropEffects.Move);
}
catch
{
// Ignore
}
}
private void LstProfiles_PointerReleased(object? sender, PointerReleasedEventArgs e)
{
_dragStartPoint = null;
}
private void LstProfiles_DragOver(object? sender, DragEventArgs e)
{
if (!e.DataTransfer.Contains(LstProfilesRowFormat))
{
e.DragEffects = DragDropEffects.None;
return;
}
e.DragEffects = DragDropEffects.Move;
}
private void LstProfiles_Drop(object? sender, DragEventArgs e)
{
if (!e.DataTransfer.Contains(LstProfilesRowFormat))
{
return;
}
ProfileItemModel? sourceItem = null;
foreach (var item in e.DataTransfer.Items)
{
if (!item.Formats.Contains(LstProfilesRowFormat))
{
continue;
}
if (item.TryGetRaw(LstProfilesRowFormat) is not ProfileItemModel model)
{
continue;
}
sourceItem = model;
break;
}
if (sourceItem == null)
{
return;
}
if (e.Source is not Visual visualTarget)
{
return;
}
var targetRow = visualTarget.FindAncestorOfType<DataGridRow>(true);
if (targetRow is not { DataContext: ProfileItemModel targetItem })
{
return;
}
if (ReferenceEquals(sourceItem, targetItem))
{
return;
}
if (lstProfiles.ItemsSource is not IList<ProfileItemModel> items)
{
return;
}
var oldIndex = items.IndexOf(sourceItem);
var newIndex = items.IndexOf(targetItem);
if (oldIndex >= 0 && newIndex >= 0)
{
ViewModel?.MoveServerTo(oldIndex, targetItem);
}
}
#endregion Drag and Drop
}
+1 -3
View File
@@ -16,12 +16,10 @@
<ItemGroup>
<PackageReference Include="Avalonia.AvaloniaEdit" />
<PackageReference Include="Avalonia.Controls.DataGrid">
<TreatAsUsed>true</TreatAsUsed>
</PackageReference>
<PackageReference Include="Avalonia.Desktop" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="AvaloniaUI.DiagnosticsSupport" />
<PackageReference Include="DialogHost.Avalonia" />
<PackageReference Include="ProDataGrid" />
<PackageReference Include="ReactiveUI.Avalonia" />
<PackageReference Include="Semi.Avalonia" />
<PackageReference Include="Semi.Avalonia.AvaloniaEdit" />