Skip to content

Commit 66603dc

Browse files
committed
拆分引导顺序逻辑,稍微完善UI
1 parent 6646d97 commit 66603dc

4 files changed

Lines changed: 209 additions & 114 deletions

File tree

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
using System;
2+
using System.Windows;
3+
using System.Windows.Controls;
4+
using System.Windows.Input;
5+
using System.Windows.Media;
6+
using Microsoft.Xaml.Behaviors;
7+
using ExHyperV.Models;
8+
9+
namespace ExHyperV.Behaviors
10+
{
11+
public class ListBoxDragDropBehavior : Behavior<System.Windows.Controls.ListBox>
12+
{
13+
private Point _startPoint;
14+
private bool _isDragging = false;
15+
16+
public static readonly DependencyProperty MoveItemCommandProperty =
17+
DependencyProperty.Register(nameof(MoveItemCommand), typeof(ICommand), typeof(ListBoxDragDropBehavior));
18+
19+
public ICommand MoveItemCommand
20+
{
21+
get => (ICommand)GetValue(MoveItemCommandProperty);
22+
set => SetValue(MoveItemCommandProperty, value);
23+
}
24+
25+
public static readonly DependencyProperty DropCompletedCommandProperty =
26+
DependencyProperty.Register(nameof(DropCompletedCommand), typeof(ICommand), typeof(ListBoxDragDropBehavior));
27+
28+
public ICommand DropCompletedCommand
29+
{
30+
get => (ICommand)GetValue(DropCompletedCommandProperty);
31+
set => SetValue(DropCompletedCommandProperty, value);
32+
}
33+
34+
protected override void OnAttached()
35+
{
36+
base.OnAttached();
37+
AssociatedObject.PreviewMouseLeftButtonDown += OnPreviewMouseLeftButtonDown;
38+
AssociatedObject.PreviewMouseMove += OnPreviewMouseMove;
39+
AssociatedObject.DragOver += OnDragOver;
40+
AssociatedObject.Drop += OnDrop;
41+
}
42+
43+
protected override void OnDetaching()
44+
{
45+
base.OnDetaching();
46+
AssociatedObject.PreviewMouseLeftButtonDown -= OnPreviewMouseLeftButtonDown;
47+
AssociatedObject.PreviewMouseMove -= OnPreviewMouseMove;
48+
AssociatedObject.DragOver -= OnDragOver;
49+
AssociatedObject.Drop -= OnDrop;
50+
}
51+
52+
private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
53+
{
54+
_startPoint = e.GetPosition(null);
55+
}
56+
57+
private void OnPreviewMouseMove(object sender, MouseEventArgs e)
58+
{
59+
if (e.LeftButton == MouseButtonState.Pressed && !_isDragging)
60+
{
61+
Point position = e.GetPosition(null);
62+
if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance ||
63+
Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance)
64+
{
65+
var item = FindVisualParent<ListBoxItem>(e.OriginalSource as DependencyObject);
66+
if (item != null)
67+
{
68+
_isDragging = true;
69+
item.Opacity = 0.6;
70+
71+
System.Windows.DragDrop.DoDragDrop(item, item.DataContext, System.Windows.DragDropEffects.Move);
72+
item.Opacity = 1.0;
73+
_isDragging = false;
74+
}
75+
}
76+
}
77+
}
78+
79+
80+
private void OnDragOver(object sender, System.Windows.DragEventArgs e)
81+
{
82+
if (e.Data.GetDataPresent(typeof(BootOrderItem)))
83+
{
84+
var sourceData = e.Data.GetData(typeof(BootOrderItem)) as BootOrderItem;
85+
var targetItem = FindVisualParent<ListBoxItem>(e.OriginalSource as DependencyObject);
86+
87+
if (targetItem != null && sourceData != null)
88+
{
89+
var targetData = targetItem.DataContext as BootOrderItem;
90+
if (sourceData != targetData)
91+
{
92+
Point relativePos = e.GetPosition(targetItem);
93+
double threshold = targetItem.ActualHeight / 4;
94+
95+
if (MoveItemCommand?.CanExecute(null) == true)
96+
{
97+
MoveItemCommand.Execute(new DragMoveArgs
98+
{
99+
Source = sourceData,
100+
Target = targetData,
101+
RelativeY = relativePos.Y,
102+
Threshold = threshold
103+
});
104+
}
105+
}
106+
}
107+
}
108+
109+
e.Effects = System.Windows.DragDropEffects.Move;
110+
e.Handled = true;
111+
}
112+
113+
114+
private void OnDrop(object sender, System.Windows.DragEventArgs e)
115+
{
116+
_isDragging = false;
117+
if (DropCompletedCommand?.CanExecute(null) == true)
118+
{
119+
DropCompletedCommand.Execute(null);
120+
}
121+
e.Handled = true;
122+
}
123+
124+
private static T FindVisualParent<T>(DependencyObject child) where T : DependencyObject
125+
{
126+
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
127+
if (parentObject == null) return null;
128+
if (parentObject is T parent) return parent;
129+
return FindVisualParent<T>(parentObject);
130+
}
131+
}
132+
133+
public class DragMoveArgs
134+
{
135+
public BootOrderItem Source { get; set; }
136+
public BootOrderItem Target { get; set; }
137+
public double RelativeY { get; set; }
138+
public double Threshold { get; set; }
139+
}
140+
}

src/ViewModels/VirtualMachinesPageViewModel.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.Diagnostics;
1414
using System.ComponentModel;
1515
using System.IO;
16+
using ExHyperV.Behaviors;
1617

1718
namespace ExHyperV.ViewModels
1819
{
@@ -2628,6 +2629,41 @@ public async Task SilentSaveBootOrderAsync()
26282629
}
26292630
}
26302631

2632+
[RelayCommand]
2633+
private void ReorderBootItem(DragMoveArgs args)
2634+
{
2635+
if (SelectedVm == null || args == null) return;
2636+
2637+
var list = SelectedVm.BootOrderItems;
2638+
int oldIndex = list.IndexOf(args.Source);
2639+
int newIndex = list.IndexOf(args.Target);
2640+
2641+
if (oldIndex == -1 || newIndex == -1) return;
2642+
2643+
// 之前的 1/3 阈值逻辑迁移到这里进行最终判定
2644+
if (newIndex > oldIndex) // 向下拖
2645+
{
2646+
if (args.RelativeY < args.Threshold) return;
2647+
}
2648+
else // 向上拖
2649+
{
2650+
if (args.RelativeY > (args.Threshold * 2)) return; // 对应 targetItem.ActualHeight - threshold
2651+
}
2652+
2653+
// 执行移动
2654+
list.Move(oldIndex, newIndex);
2655+
2656+
// 更新 IsLast 标记以维护 UI 箭头显示(如果需要)
2657+
foreach (var item in list) item.IsLast = false;
2658+
list.Last().IsLast = true;
2659+
}
2660+
2661+
[RelayCommand]
2662+
private async Task SaveBootOrder()
2663+
{
2664+
System.Diagnostics.Debug.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] [VM-SAVE-TASK] 执行异步保存...");
2665+
await SilentSaveBootOrderAsync();
2666+
}
26312667

26322668
// ----------------------------------------------------------------------------------
26332669
// GPU 管理模块 - 列表与基础操作

src/Views/Components/VmBootSettingsView.xaml

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
66
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
77
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
8+
xmlns:behaviors="clr-namespace:ExHyperV.Behaviors"
89
mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="800">
910

1011
<Grid>
@@ -13,30 +14,35 @@
1314
<RowDefinition Height="*"/>
1415
</Grid.RowDefinitions>
1516

16-
<Grid Grid.Row="0" Margin="24,16,24,12">
17+
<Grid Grid.Row="0" Margin="24,20,24,16">
1718
<Grid.ColumnDefinitions>
1819
<ColumnDefinition Width="*"/>
1920
<ColumnDefinition Width="Auto"/>
2021
</Grid.ColumnDefinitions>
2122
<StackPanel VerticalAlignment="Center">
22-
<TextBlock Text="引导顺序" FontSize="20" FontWeight="SemiBold" Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"/>
23-
<TextBlock Text="按住卡片上下拖动以调整启动优先级" FontSize="12" Opacity="0.6" Margin="0,4,0,0" Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"/>
23+
<TextBlock Text="引导顺序" FontSize="22" FontWeight="Normal" Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"/>
24+
<TextBlock Text="上下拖动以调整优先级" FontSize="13" Opacity="0.6" Margin="0,6,0,0" Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"/>
2425
</StackPanel>
2526
<ui:Button Grid.Column="1" Appearance="Transparent" Padding="8" Command="{Binding GoBackToDashboardCommand}">
26-
<ui:SymbolIcon Symbol="ArrowLeft24" FontSize="18"/>
27+
<ui:SymbolIcon Symbol="ArrowLeft24" FontSize="20"/>
2728
</ui:Button>
2829
</Grid>
2930

3031
<ListBox x:Name="BootListBox"
3132
Grid.Row="1"
32-
Margin="24,8,24,24"
33+
Margin="24,4,24,24"
3334
Background="Transparent"
3435
BorderThickness="0"
3536
ItemsSource="{Binding SelectedVm.BootOrderItems}"
3637
AllowDrop="True"
37-
DragOver="BootListBox_DragOver"
38-
Drop="BootListBox_Drop"
3938
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
39+
40+
<b:Interaction.Behaviors>
41+
<behaviors:ListBoxDragDropBehavior
42+
MoveItemCommand="{Binding ReorderBootItemCommand}"
43+
DropCompletedCommand="{Binding SaveBootOrderCommand}"/>
44+
</b:Interaction.Behaviors>
45+
4046
<ListBox.ItemsPanel>
4147
<ItemsPanelTemplate>
4248
<StackPanel x:Name="ItemsPanel" IsItemsHost="True">
@@ -55,10 +61,8 @@
5561
<Style TargetType="ListBoxItem">
5662
<Setter Property="Background" Value="Transparent"/>
5763
<Setter Property="Padding" Value="0"/>
58-
<Setter Property="Margin" Value="0,0,0,8"/>
64+
<Setter Property="Margin" Value="0,0,0,10"/>
5965
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
60-
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="Card_PreviewMouseLeftButtonDown"/>
61-
<EventSetter Event="PreviewMouseMove" Handler="Card_PreviewMouseMove"/>
6266
<Setter Property="Template">
6367
<Setter.Value>
6468
<ControlTemplate TargetType="ListBoxItem">
@@ -75,22 +79,32 @@
7579
<DataTemplate>
7680
<Border Background="{ui:ThemeResource ControlFillColorDefaultBrush}"
7781
BorderBrush="{ui:ThemeResource CardStrokeColorDefaultBrush}"
78-
BorderThickness="1" CornerRadius="8" Padding="16,20">
82+
BorderThickness="1" CornerRadius="8" Padding="18,18">
7983
<Grid>
8084
<Grid.ColumnDefinitions>
8185
<ColumnDefinition Width="Auto"/>
8286
<ColumnDefinition Width="*"/>
8387
<ColumnDefinition Width="Auto"/>
8488
</Grid.ColumnDefinitions>
8589

86-
<ui:FontIcon Grid.Column="0" Glyph="{Binding Icon}" FontSize="20" Margin="0,0,16,0" Opacity="0.8"/>
90+
<ui:FontIcon Grid.Column="0"
91+
Glyph="{Binding Icon}"
92+
FontSize="20"
93+
Margin="0,0,18,0"
94+
FontFamily="{DynamicResource SegoeFluentIcons}"
95+
Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"/>
8796

88-
<StackPanel Grid.Column="1" VerticalAlignment="Center">
89-
<TextBlock Text="{Binding Name}" FontSize="16" FontWeight="Medium" Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"/>
90-
<TextBlock Text="{Binding Description}" FontSize="12" Opacity="0.5" Margin="0,4,0,0" Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"/>
97+
<StackPanel Grid.Column="1" Orientation="Horizontal" VerticalAlignment="Center">
98+
<TextBlock Text="{Binding Name}" FontSize="15" FontWeight="Medium" Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"/>
99+
<TextBlock Text="{Binding Description}" FontSize="14" Opacity="0.5" Margin="16,0,0,0" VerticalAlignment="Center" Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}" TextTrimming="CharacterEllipsis"/>
91100
</StackPanel>
92101

93-
<ui:FontIcon Grid.Column="2" Glyph="&#xE76F;" FontFamily="{DynamicResource SegoeFluentIcons}" FontSize="18" Opacity="0.4" VerticalAlignment="Center"/>
102+
<ui:FontIcon Grid.Column="2"
103+
Glyph="&#xE700;"
104+
FontFamily="{DynamicResource SegoeFluentIcons}"
105+
FontSize="18"
106+
Foreground="{ui:ThemeResource TextFillColorSecondaryBrush}"
107+
VerticalAlignment="Center"/>
94108
</Grid>
95109
</Border>
96110
</DataTemplate>

0 commit comments

Comments
 (0)