From 8b93d35766db7f17ed479f4a9684ef6a6629c486 Mon Sep 17 00:00:00 2001 From: DHR60 <192860629+DHR60@users.noreply.github.com> Date: Sun, 1 Nov 2026 12:34:24 +0000 Subject: [PATCH] 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] * Remove Avalonia.Controls.DataGrid * Add ProDataGrid Feature --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com> --- v2rayN/Directory.Packages.props | 5 +- v2rayN/ServiceLib/Handler/ConfigHandler.cs | 61 ++++ v2rayN/ServiceLib/Resx/ResUI.Designer.cs | 9 + v2rayN/ServiceLib/Resx/ResUI.resx | 3 + v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx | 3 + .../ViewModels/ProfilesViewModel.cs | 27 ++ v2rayN/v2rayN.Desktop/App.axaml | 3 +- .../Views/AddGroupServerWindow.axaml | 12 +- .../Views/AddGroupServerWindow.axaml.cs | 6 - .../Views/ProfilesSelectWindow.axaml | 6 +- .../Views/ProfilesSelectWindow.axaml.cs | 6 - .../v2rayN.Desktop/Views/ProfilesView.axaml | 97 ++++- .../Views/ProfilesView.axaml.cs | 335 ++++++++++-------- v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj | 4 +- 14 files changed, 393 insertions(+), 184 deletions(-) diff --git a/v2rayN/Directory.Packages.props b/v2rayN/Directory.Packages.props index 292b44f7..d35b38ea 100644 --- a/v2rayN/Directory.Packages.props +++ b/v2rayN/Directory.Packages.props @@ -6,8 +6,7 @@ - - + @@ -32,4 +31,4 @@ - \ No newline at end of file + diff --git a/v2rayN/ServiceLib/Handler/ConfigHandler.cs b/v2rayN/ServiceLib/Handler/ConfigHandler.cs index 3bfa1f23..7daad49b 100644 --- a/v2rayN/ServiceLib/Handler/ConfigHandler.cs +++ b/v2rayN/ServiceLib/Handler/ConfigHandler.cs @@ -540,6 +540,67 @@ public static class ConfigHandler return await Task.FromResult(0); } + public static Task MoveServersTo( + Config config, + IReadOnlyList orderedProfileIds, + IReadOnlyList 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); + } + /// /// Add a custom server configuration from a file /// Copies the configuration file to the app's config directory diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs index 08a139bb..3c9847f0 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs +++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs @@ -978,6 +978,15 @@ namespace ServiceLib.Resx { } } + /// + /// 查找类似 Columns 的本地化字符串。 + /// + public static string menuColumns { + get { + return ResourceManager.GetString("menuColumns", resourceCulture); + } + } + /// /// 查找类似 Close Connection 的本地化字符串。 /// diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx index 39f02c5d..49d63db7 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.resx @@ -1905,4 +1905,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if Add [MASQUE] + + Columns + \ No newline at end of file diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx index 4d97e994..70b03202 100644 --- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx +++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx @@ -1897,4 +1897,7 @@ 添加 [MASQUE] + + 列 + \ No newline at end of file diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index 3d5a291f..0f6c859d 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -702,6 +702,33 @@ public partial class ProfilesViewModel : MyReactiveObject } } + public async Task MoveServersTo( + IReadOnlyList 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? lstSelected; diff --git a/v2rayN/v2rayN.Desktop/App.axaml b/v2rayN/v2rayN.Desktop/App.axaml index a2de69b6..e64e1613 100644 --- a/v2rayN/v2rayN.Desktop/App.axaml +++ b/v2rayN/v2rayN.Desktop/App.axaml @@ -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 @@ + ToolTipText="{Binding RunningServerToolTipText, FallbackValue={x:Static service:Global.AppName}}"> + SelectionMode="Extended" + ShowRowNumbers="True"> @@ -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"> // 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 } } - 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(); diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml index 17eec3ae..3adb5a8b 100644 --- a/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml @@ -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}" /> @@ -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"> diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs index 6a165d37..22a010dc 100644 --- a/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs @@ -14,7 +14,6 @@ public partial class ProfilesSelectWindow : WindowBase 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 } } - 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 diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml index 305e61b5..2d142e41 100644 --- a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml +++ b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml @@ -16,6 +16,48 @@ mc:Ignorable="d"> + + + + + + + + + + + + + + + + + + + + + + + + @@ -79,6 +121,15 @@ + + + + + + + + + IsReadOnly="False" + ItemsSource="{Binding ProfileItems}" + ShowRowNumbers="True"> @@ -212,12 +270,13 @@ Width="80" Binding="{Binding ConfigType}" Header="{x:Static resx:ResUI.LvServiceType}" + IsReadOnly="True" Tag="ConfigType" /> - - - - + @@ -240,31 +299,36 @@ Width="120" Binding="{Binding Address}" Header="{x:Static resx:ResUI.LvAddress}" + IsReadOnly="True" Tag="Address" /> - - - - + - - - - + diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs index 43ccba14..2f7e8318 100644 --- a/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/ProfilesView.axaml.cs @@ -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 { 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 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 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 } } - 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 #endregion UI - #region Drag and Drop + //#region Drag and Drop - private static readonly DataFormat LstProfilesRowFormat = - DataFormat.CreateInProcessFormat("LstProfilesRow"); + //private static readonly DataFormat LstProfilesRowFormat = + // DataFormat.CreateInProcessFormat("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(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(true); + // if (targetRow is not { DataContext: ProfileItemModel targetItem }) + // { + // return; + // } + // if (ReferenceEquals(sourceItem, targetItem)) + // { + // return; + // } + // if (lstProfiles.ItemsSource is not IList 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(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(true); - if (targetRow is not { DataContext: ProfileItemModel targetItem }) - { - return; - } - if (ReferenceEquals(sourceItem, targetItem)) - { - return; - } - if (lstProfiles.ItemsSource is not IList 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 } diff --git a/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj b/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj index fb2274e8..fb8d9ba7 100644 --- a/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj +++ b/v2rayN/v2rayN.Desktop/v2rayN.Desktop.csproj @@ -16,12 +16,10 @@ - - true - +