A:附加提交

This commit is contained in:
jimmy committed 2025-07-31 15:01:04 +08:00
1 parent a7136798f5
commit c0cc9b0b81
1 file changed
+58 -39
@@ -35,6 +35,7 @@ public partial class NetView : Window
private const int GWL_EXSTYLE = -20; private const int GWL_EXSTYLE = -20;
private const int WS_EX_TRANSPARENT = 0x00000020; private const int WS_EX_TRANSPARENT = 0x00000020;
private const int WS_EX_TOOLWINDOW = 0x00000080;
private const int SPI_SETDRAGFULLWINDOWS = 0x0025; private const int SPI_SETDRAGFULLWINDOWS = 0x0025;
public NetView() public NetView()
@@ -42,10 +43,10 @@ public partial class NetView : Window
InitializeComponent(); InitializeComponent();
InitializeTrayIcon(); InitializeTrayIcon();
this.Loaded += NetView_Loaded; this.Loaded += NetView_Loaded;
// Prevent window snapping by setting ResizeMode appropriately // Prevent window snapping by setting ResizeMode appropriately
this.ResizeMode = ResizeMode.NoResize; this.ResizeMode = ResizeMode.NoResize;
// Initialize double-click timer // Initialize double-click timer
InitializeDoubleClickTimer(); InitializeDoubleClickTimer();
} }
@@ -57,10 +58,13 @@ public partial class NetView : Window
{ {
ResetToDefaultPosition(); ResetToDefaultPosition();
} }
// 设置窗口为工具窗口,隐藏在Alt+Tab中
HideFromAltTab();
// Disable automatic window arrangement features // Disable automatic window arrangement features
DisableWindowSnapping(); DisableWindowSnapping();
// Populate network interfaces in context menu // Populate network interfaces in context menu
PopulateNetworkMenu(); PopulateNetworkMenu();
} }
@@ -75,12 +79,12 @@ public partial class NetView : Window
{ {
// Clear existing items // Clear existing items
NetworkSelectionMenuItem.Items.Clear(); NetworkSelectionMenuItem.Items.Clear();
// Add network interfaces from ViewModel // Add network interfaces from ViewModel
foreach (var netInterface in viewModel.NetworkInterfaces) foreach (var netInterface in viewModel.NetworkInterfaces)
{ {
var menuItem = new System.Windows.Controls.MenuItem(); var menuItem = new System.Windows.Controls.MenuItem();
// Create header with status indicator // Create header with status indicator
var headerText = netInterface.Name; var headerText = netInterface.Name;
if (netInterface.IsConnected) if (netInterface.IsConnected)
@@ -91,29 +95,32 @@ public partial class NetView : Window
{ {
headerText += " [未连接]"; headerText += " [未连接]";
} }
menuItem.Header = headerText; menuItem.Header = headerText;
menuItem.IsCheckable = true; menuItem.IsCheckable = true;
menuItem.IsChecked = netInterface == viewModel.SelectedInterface; menuItem.IsChecked = netInterface == viewModel.SelectedInterface;
menuItem.Tag = netInterface; menuItem.Tag = netInterface;
// Set different styles for connected/disconnected // Set different styles for connected/disconnected
if (netInterface.IsConnected) if (netInterface.IsConnected)
{ {
menuItem.Foreground = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Green); menuItem.Foreground =
new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Green);
} }
else else
{ {
menuItem.Foreground = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Gray); menuItem.Foreground =
new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Gray);
} }
menuItem.Click += (s, e) => { menuItem.Click += (s, e) =>
if (s is System.Windows.Controls.MenuItem clickedItem && {
if (s is System.Windows.Controls.MenuItem clickedItem &&
clickedItem.Tag is Shell.ViewModel.NetworkInterfaceItem selectedInterface) clickedItem.Tag is Shell.ViewModel.NetworkInterfaceItem selectedInterface)
{ {
// Update selection in ViewModel // Update selection in ViewModel
viewModel.SelectedInterface = selectedInterface; viewModel.SelectedInterface = selectedInterface;
// Update check states // Update check states
foreach (System.Windows.Controls.MenuItem item in NetworkSelectionMenuItem.Items) foreach (System.Windows.Controls.MenuItem item in NetworkSelectionMenuItem.Items)
{ {
@@ -121,7 +128,7 @@ public partial class NetView : Window
} }
} }
}; };
NetworkSelectionMenuItem.Items.Add(menuItem); NetworkSelectionMenuItem.Items.Add(menuItem);
} }
} }
@@ -159,6 +166,17 @@ public partial class NetView : Window
} }
} }
private void HideFromAltTab()
{
// 设置窗口为工具窗口,这样它就不会出现在Alt+Tab中
var hwnd = new WindowInteropHelper(this).Handle;
if (hwnd != IntPtr.Zero)
{
var extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TOOLWINDOW);
}
}
private void InitializeTrayIcon() private void InitializeTrayIcon()
{ {
_trayIconManager = new TrayIconManager(this); _trayIconManager = new TrayIconManager(this);
@@ -180,6 +198,7 @@ public partial class NetView : Window
{ {
// Single click - no action needed for now // Single click - no action needed for now
} }
_isDoubleClick = false; _isDoubleClick = false;
} }
@@ -204,7 +223,7 @@ public partial class NetView : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
System.Windows.MessageBox.Show($"执行双击动作失败: {ex.Message}", "错误", System.Windows.MessageBox.Show($"执行双击动作失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error); MessageBoxButton.OK, MessageBoxImage.Error);
} }
} }
@@ -238,7 +257,7 @@ public partial class NetView : Window
// Log but don't prevent shutdown // Log but don't prevent shutdown
System.Diagnostics.Debug.WriteLine($"Error closing TrafficAnalysisWindow: {ex.Message}"); System.Diagnostics.Debug.WriteLine($"Error closing TrafficAnalysisWindow: {ex.Message}");
} }
// Close SettingsWindow if it exists // Close SettingsWindow if it exists
try try
{ {
@@ -252,7 +271,7 @@ public partial class NetView : Window
// Log but don't prevent shutdown // Log but don't prevent shutdown
System.Diagnostics.Debug.WriteLine($"Error closing SettingsWindow: {ex.Message}"); System.Diagnostics.Debug.WriteLine($"Error closing SettingsWindow: {ex.Message}");
} }
_trayIconManager?.Dispose(); _trayIconManager?.Dispose();
System.Windows.Application.Current.Shutdown(); System.Windows.Application.Current.Shutdown();
} }
@@ -274,7 +293,7 @@ public partial class NetView : Window
{ {
_isPositionLocked = !_isPositionLocked; _isPositionLocked = !_isPositionLocked;
LockPositionMenuItem.IsChecked = _isPositionLocked; LockPositionMenuItem.IsChecked = _isPositionLocked;
// Don't change ResizeMode to maintain consistent window behavior // Don't change ResizeMode to maintain consistent window behavior
// The dragging logic will check _isPositionLocked instead // The dragging logic will check _isPositionLocked instead
} }
@@ -313,7 +332,7 @@ public partial class NetView : Window
{ {
_snapToScreen = !_snapToScreen; _snapToScreen = !_snapToScreen;
SnapToScreenMenuItem.IsChecked = _snapToScreen; SnapToScreenMenuItem.IsChecked = _snapToScreen;
if (_snapToScreen) if (_snapToScreen)
{ {
SnapToScreen(); SnapToScreen();
@@ -325,7 +344,7 @@ public partial class NetView : Window
var workArea = SystemParameters.WorkArea; var workArea = SystemParameters.WorkArea;
var left = Math.Max(workArea.Left, Math.Min(this.Left, workArea.Right - this.Width)); var left = Math.Max(workArea.Left, Math.Min(this.Left, workArea.Right - this.Width));
var top = Math.Max(workArea.Top, Math.Min(this.Top, workArea.Bottom - this.Height)); var top = Math.Max(workArea.Top, Math.Min(this.Top, workArea.Bottom - this.Height));
this.Left = left; this.Left = left;
this.Top = top; this.Top = top;
} }
@@ -334,10 +353,10 @@ public partial class NetView : Window
{ {
_showDetailedInfo = !_showDetailedInfo; _showDetailedInfo = !_showDetailedInfo;
DetailedInfoMenuItem.IsChecked = _showDetailedInfo; DetailedInfoMenuItem.IsChecked = _showDetailedInfo;
// The window will automatically resize based on content // The window will automatically resize based on content
// No need to manually set height anymore due to SizeToContent="WidthAndHeight" // No need to manually set height anymore due to SizeToContent="WidthAndHeight"
// You can trigger a re-layout if needed // You can trigger a re-layout if needed
this.InvalidateMeasure(); this.InvalidateMeasure();
this.UpdateLayout(); this.UpdateLayout();
@@ -350,7 +369,7 @@ public partial class NetView : Window
private void ExitApplication_Click(object sender, RoutedEventArgs e) private void ExitApplication_Click(object sender, RoutedEventArgs e)
{ {
var result = System.Windows.MessageBox.Show("确定要退出程序吗?", "确认退出", var result = System.Windows.MessageBox.Show("确定要退出程序吗?", "确认退出",
MessageBoxButton.YesNo, MessageBoxImage.Question); MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes) if (result == MessageBoxResult.Yes)
{ {
@@ -366,7 +385,7 @@ public partial class NetView : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
System.Windows.MessageBox.Show($"无法打开流量分析窗口: {ex.Message}", "错误", System.Windows.MessageBox.Show($"无法打开流量分析窗口: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error); MessageBoxButton.OK, MessageBoxImage.Error);
} }
} }
@@ -379,7 +398,7 @@ public partial class NetView : Window
} }
catch (Exception ex) catch (Exception ex)
{ {
System.Windows.MessageBox.Show($"无法打开设置窗口: {ex.Message}", "错误", System.Windows.MessageBox.Show($"无法打开设置窗口: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error); MessageBoxButton.OK, MessageBoxImage.Error);
} }
} }
@@ -422,13 +441,13 @@ public partial class NetView : Window
protected override void OnLocationChanged(EventArgs e) protected override void OnLocationChanged(EventArgs e)
{ {
base.OnLocationChanged(e); base.OnLocationChanged(e);
// Only check snap to screen if that option is enabled // Only check snap to screen if that option is enabled
if (_snapToScreen && !_isPositionLocked) if (_snapToScreen && !_isPositionLocked)
{ {
SnapToScreen(); SnapToScreen();
} }
// Perform boundary check after drag is complete (with delay to avoid flicker) // Perform boundary check after drag is complete (with delay to avoid flicker)
if (!_isPositionLocked) if (!_isPositionLocked)
{ {
@@ -437,24 +456,24 @@ public partial class NetView : Window
} }
private System.Windows.Threading.DispatcherTimer? _boundaryCheckTimer; private System.Windows.Threading.DispatcherTimer? _boundaryCheckTimer;
private void CheckBoundariesDelayed() private void CheckBoundariesDelayed()
{ {
// Cancel previous timer if exists // Cancel previous timer if exists
_boundaryCheckTimer?.Stop(); _boundaryCheckTimer?.Stop();
// Create new timer for delayed boundary check // Create new timer for delayed boundary check
_boundaryCheckTimer = new System.Windows.Threading.DispatcherTimer _boundaryCheckTimer = new System.Windows.Threading.DispatcherTimer
{ {
Interval = TimeSpan.FromMilliseconds(150) // Delay to avoid flicker during drag Interval = TimeSpan.FromMilliseconds(150) // Delay to avoid flicker during drag
}; };
_boundaryCheckTimer.Tick += (s, e) => _boundaryCheckTimer.Tick += (s, e) =>
{ {
_boundaryCheckTimer.Stop(); _boundaryCheckTimer.Stop();
SnapBackToScreen(); SnapBackToScreen();
}; };
_boundaryCheckTimer.Start(); _boundaryCheckTimer.Start();
} }
@@ -463,18 +482,18 @@ public partial class NetView : Window
var workArea = SystemParameters.WorkArea; var workArea = SystemParameters.WorkArea;
var originalLeft = this.Left; var originalLeft = this.Left;
var originalTop = this.Top; var originalTop = this.Top;
// Calculate bounds with some tolerance (allow partial off-screen) // Calculate bounds with some tolerance (allow partial off-screen)
var tolerance = 20; // Allow 20 pixels to be off-screen var tolerance = 20; // Allow 20 pixels to be off-screen
var minLeft = workArea.Left - (this.Width - tolerance); var minLeft = workArea.Left - (this.Width - tolerance);
var maxLeft = workArea.Right - tolerance; var maxLeft = workArea.Right - tolerance;
var minTop = workArea.Top - (this.Height - tolerance); var minTop = workArea.Top - (this.Height - tolerance);
var maxTop = workArea.Bottom - tolerance; var maxTop = workArea.Bottom - tolerance;
// Adjust position if outside bounds // Adjust position if outside bounds
var newLeft = Math.Max(minLeft, Math.Min(this.Left, maxLeft)); var newLeft = Math.Max(minLeft, Math.Min(this.Left, maxLeft));
var newTop = Math.Max(minTop, Math.Min(this.Top, maxTop)); var newTop = Math.Max(minTop, Math.Min(this.Top, maxTop));
// Only animate if position actually changed // Only animate if position actually changed
if (Math.Abs(newLeft - originalLeft) > 1 || Math.Abs(newTop - originalTop) > 1) if (Math.Abs(newLeft - originalLeft) > 1 || Math.Abs(newTop - originalTop) > 1)
{ {
@@ -485,20 +504,20 @@ public partial class NetView : Window
private void AnimateToPosition(double targetLeft, double targetTop) private void AnimateToPosition(double targetLeft, double targetTop)
{ {
var duration = TimeSpan.FromMilliseconds(200); var duration = TimeSpan.FromMilliseconds(200);
var leftAnimation = new System.Windows.Media.Animation.DoubleAnimation( var leftAnimation = new System.Windows.Media.Animation.DoubleAnimation(
this.Left, targetLeft, duration) this.Left, targetLeft, duration)
{ {
EasingFunction = new System.Windows.Media.Animation.QuadraticEase() EasingFunction = new System.Windows.Media.Animation.QuadraticEase()
}; };
var topAnimation = new System.Windows.Media.Animation.DoubleAnimation( var topAnimation = new System.Windows.Media.Animation.DoubleAnimation(
this.Top, targetTop, duration) this.Top, targetTop, duration)
{ {
EasingFunction = new System.Windows.Media.Animation.QuadraticEase() EasingFunction = new System.Windows.Media.Animation.QuadraticEase()
}; };
this.BeginAnimation(Window.LeftProperty, leftAnimation); this.BeginAnimation(Window.LeftProperty, leftAnimation);
this.BeginAnimation(Window.TopProperty, topAnimation); this.BeginAnimation(Window.TopProperty, topAnimation);
} }
} }