A:增加网络占用TOP展示
This commit is contained in:
1 parent
1f06ca6cac
commit
1c56007afd
11 files changed
+891
-114
No files matched your search
@@ -87,6 +87,15 @@ public class AppSetting
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AutoStart { get; set; } = false;
|
public bool AutoStart { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否显示网速Top榜 (只在横向布局时可用)
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowNetworkTopList { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 网速Top榜显示数量 (1-5)
|
||||||
|
/// </summary>
|
||||||
|
public int NetworkTopListCount { get; set; } = 3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新时间
|
/// 更新时间
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ public class NetVizorDbContext : IDisposable
|
|||||||
DoubleClickAction INTEGER DEFAULT 0,
|
DoubleClickAction INTEGER DEFAULT 0,
|
||||||
RunAsAdmin INTEGER DEFAULT 0,
|
RunAsAdmin INTEGER DEFAULT 0,
|
||||||
AutoStart INTEGER DEFAULT 0,
|
AutoStart INTEGER DEFAULT 0,
|
||||||
|
ShowNetworkTopList INTEGER DEFAULT 0,
|
||||||
|
NetworkTopListCount INTEGER DEFAULT 3,
|
||||||
UpdateTime INTEGER NOT NULL
|
UpdateTime INTEGER NOT NULL
|
||||||
)");
|
)");
|
||||||
|
|
||||||
@@ -282,7 +284,8 @@ public class NetVizorDbContext : IDisposable
|
|||||||
var needsMigration = columns.Contains("WindowWidth") || columns.Contains("WindowHeight") ||
|
var needsMigration = columns.Contains("WindowWidth") || columns.Contains("WindowHeight") ||
|
||||||
columns.Contains("Theme") || columns.Contains("Language") ||
|
columns.Contains("Theme") || columns.Contains("Language") ||
|
||||||
columns.Contains("MonitoringEnabled") ||
|
columns.Contains("MonitoringEnabled") ||
|
||||||
!columns.Contains("IsClickThrough") || !columns.Contains("TextColor");
|
!columns.Contains("IsClickThrough") || !columns.Contains("TextColor") ||
|
||||||
|
!columns.Contains("ShowNetworkTopList") || !columns.Contains("NetworkTopListCount");
|
||||||
|
|
||||||
if (needsMigration)
|
if (needsMigration)
|
||||||
{
|
{
|
||||||
@@ -315,6 +318,8 @@ public class NetVizorDbContext : IDisposable
|
|||||||
DoubleClickAction INTEGER DEFAULT 0,
|
DoubleClickAction INTEGER DEFAULT 0,
|
||||||
RunAsAdmin INTEGER DEFAULT 0,
|
RunAsAdmin INTEGER DEFAULT 0,
|
||||||
AutoStart INTEGER DEFAULT 0,
|
AutoStart INTEGER DEFAULT 0,
|
||||||
|
ShowNetworkTopList INTEGER DEFAULT 0,
|
||||||
|
NetworkTopListCount INTEGER DEFAULT 3,
|
||||||
UpdateTime INTEGER NOT NULL
|
UpdateTime INTEGER NOT NULL
|
||||||
)");
|
)");
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ public class DataService : IDataService, IDisposable
|
|||||||
DoubleClickAction = 0, // None
|
DoubleClickAction = 0, // None
|
||||||
RunAsAdmin = false,
|
RunAsAdmin = false,
|
||||||
AutoStart = false,
|
AutoStart = false,
|
||||||
|
ShowNetworkTopList = false, // 默认关闭网速Top榜
|
||||||
|
NetworkTopListCount = 3, // 默认显示3个
|
||||||
UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ namespace Shell.Models;
|
|||||||
public class NetViewSettings : INotifyPropertyChanged
|
public class NetViewSettings : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private static NetViewSettings? _instance;
|
private static NetViewSettings? _instance;
|
||||||
|
|
||||||
private static readonly string SettingsFilePath = Path.Combine(
|
private static readonly string SettingsFilePath = Path.Combine(
|
||||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
"NetVizor", "settings.json");
|
"NetVizor", "settings.json");
|
||||||
|
|
||||||
public static NetViewSettings Instance
|
public static NetViewSettings Instance
|
||||||
@@ -21,60 +22,187 @@ public class NetViewSettings : INotifyPropertyChanged
|
|||||||
{
|
{
|
||||||
_instance = LoadSettings();
|
_instance = LoadSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 外观设置
|
// 外观设置
|
||||||
private string _textColor = "#333333";
|
private string _textColor = "#333333";
|
||||||
|
|
||||||
public string TextColor
|
public string TextColor
|
||||||
{
|
{
|
||||||
get => _textColor;
|
get => _textColor;
|
||||||
set { _textColor = value; OnPropertyChanged(); }
|
set
|
||||||
|
{
|
||||||
|
_textColor = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _backgroundColor = "#F0FFFFFF";
|
private string _backgroundColor = "#F0FFFFFF";
|
||||||
|
|
||||||
public string BackgroundColor
|
public string BackgroundColor
|
||||||
{
|
{
|
||||||
get => _backgroundColor;
|
get => _backgroundColor;
|
||||||
set { _backgroundColor = value; OnPropertyChanged(); }
|
set
|
||||||
|
{
|
||||||
|
_backgroundColor = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private double _backgroundOpacity = 94.0;
|
private double _backgroundOpacity = 94.0;
|
||||||
|
|
||||||
public double BackgroundOpacity
|
public double BackgroundOpacity
|
||||||
{
|
{
|
||||||
get => _backgroundOpacity;
|
get => _backgroundOpacity;
|
||||||
set { _backgroundOpacity = value; OnPropertyChanged(); }
|
set
|
||||||
|
{
|
||||||
|
_backgroundOpacity = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 显示设置
|
// 显示设置
|
||||||
private SpeedUnit _speedUnit = SpeedUnit.Auto;
|
private SpeedUnit _speedUnit = SpeedUnit.Auto;
|
||||||
|
|
||||||
public SpeedUnit SpeedUnit
|
public SpeedUnit SpeedUnit
|
||||||
{
|
{
|
||||||
get => _speedUnit;
|
get => _speedUnit;
|
||||||
set { _speedUnit = value; OnPropertyChanged(); }
|
set
|
||||||
|
{
|
||||||
|
_speedUnit = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _showUnit = true;
|
private bool _showUnit = true;
|
||||||
|
|
||||||
public bool ShowUnit
|
public bool ShowUnit
|
||||||
{
|
{
|
||||||
get => _showUnit;
|
get => _showUnit;
|
||||||
set { _showUnit = value; OnPropertyChanged(); }
|
set
|
||||||
|
{
|
||||||
|
_showUnit = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LayoutDirection _layoutDirection = LayoutDirection.Vertical;
|
private LayoutDirection _layoutDirection = LayoutDirection.Vertical;
|
||||||
|
|
||||||
public LayoutDirection LayoutDirection
|
public LayoutDirection LayoutDirection
|
||||||
{
|
{
|
||||||
get => _layoutDirection;
|
get => _layoutDirection;
|
||||||
set { _layoutDirection = value; OnPropertyChanged(); }
|
set
|
||||||
|
{
|
||||||
|
_layoutDirection = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 网速Top榜设置
|
||||||
|
private bool _showNetworkTopList = false;
|
||||||
|
|
||||||
|
public bool ShowNetworkTopList
|
||||||
|
{
|
||||||
|
get => _showNetworkTopList;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_showNetworkTopList = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _networkTopListCount = 3;
|
||||||
|
|
||||||
|
public int NetworkTopListCount
|
||||||
|
{
|
||||||
|
get => _networkTopListCount;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_networkTopListCount = Math.Max(1, Math.Min(5, value));
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Top榜是否可用(只有横向布局时才可用)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsTopListAvailable => LayoutDirection == LayoutDirection.Horizontal;
|
||||||
|
|
||||||
// 交互设置
|
// 交互设置
|
||||||
private DoubleClickAction _doubleClickAction = DoubleClickAction.None;
|
private DoubleClickAction _doubleClickAction = DoubleClickAction.None;
|
||||||
|
|
||||||
public DoubleClickAction DoubleClickAction
|
public DoubleClickAction DoubleClickAction
|
||||||
{
|
{
|
||||||
get => _doubleClickAction;
|
get => _doubleClickAction;
|
||||||
set { _doubleClickAction = value; OnPropertyChanged(); }
|
set
|
||||||
|
{
|
||||||
|
_doubleClickAction = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 窗口行为设置
|
||||||
|
private bool _lockPosition = false;
|
||||||
|
|
||||||
|
public bool LockPosition
|
||||||
|
{
|
||||||
|
get => _lockPosition;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_lockPosition = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _clickThrough = false;
|
||||||
|
|
||||||
|
public bool ClickThrough
|
||||||
|
{
|
||||||
|
get => _clickThrough;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_clickThrough = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _topmost = true;
|
||||||
|
|
||||||
|
public bool Topmost
|
||||||
|
{
|
||||||
|
get => _topmost;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_topmost = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _snapToScreen = false;
|
||||||
|
|
||||||
|
public bool SnapToScreen
|
||||||
|
{
|
||||||
|
get => _snapToScreen;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_snapToScreen = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _showDetailedInfo = false;
|
||||||
|
|
||||||
|
public bool ShowDetailedInfo
|
||||||
|
{
|
||||||
|
get => _showDetailedInfo;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_showDetailedInfo = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
@@ -102,7 +230,7 @@ public class NetViewSettings : INotifyPropertyChanged
|
|||||||
|
|
||||||
var json = JsonSerializer.Serialize(this, options);
|
var json = JsonSerializer.Serialize(this, options);
|
||||||
File.WriteAllText(SettingsFilePath, json);
|
File.WriteAllText(SettingsFilePath, json);
|
||||||
|
|
||||||
Log.Info("设置已保存");
|
Log.Info("设置已保存");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -122,7 +250,7 @@ public class NetViewSettings : INotifyPropertyChanged
|
|||||||
{
|
{
|
||||||
Converters = { new System.Text.Json.Serialization.JsonStringEnumConverter() }
|
Converters = { new System.Text.Json.Serialization.JsonStringEnumConverter() }
|
||||||
};
|
};
|
||||||
|
|
||||||
var settings = JsonSerializer.Deserialize<NetViewSettings>(json, options);
|
var settings = JsonSerializer.Deserialize<NetViewSettings>(json, options);
|
||||||
if (settings != null)
|
if (settings != null)
|
||||||
{
|
{
|
||||||
@@ -148,8 +276,15 @@ public class NetViewSettings : INotifyPropertyChanged
|
|||||||
SpeedUnit = SpeedUnit.Auto;
|
SpeedUnit = SpeedUnit.Auto;
|
||||||
ShowUnit = true;
|
ShowUnit = true;
|
||||||
LayoutDirection = LayoutDirection.Vertical;
|
LayoutDirection = LayoutDirection.Vertical;
|
||||||
|
ShowNetworkTopList = false;
|
||||||
|
NetworkTopListCount = 3;
|
||||||
DoubleClickAction = DoubleClickAction.None;
|
DoubleClickAction = DoubleClickAction.None;
|
||||||
|
LockPosition = false;
|
||||||
|
ClickThrough = false;
|
||||||
|
Topmost = true;
|
||||||
|
SnapToScreen = false;
|
||||||
|
ShowDetailedInfo = false;
|
||||||
|
|
||||||
Log.Info("设置已恢复默认值");
|
Log.Info("设置已恢复默认值");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Assets\Icons\"/>
|
<Folder Include="Assets\Icons\"/>
|
||||||
|
<Folder Include="Services\"/>
|
||||||
<Folder Include="wwwroot\" />
|
<Folder Include="wwwroot\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<d:UserControl.DataContext>
|
<d:UserControl.DataContext>
|
||||||
<viewModel:NetworkMonitorViewModel />
|
<viewModel:NetworkMonitorViewModel />
|
||||||
</d:UserControl.DataContext>
|
</d:UserControl.DataContext>
|
||||||
|
|
||||||
<Border
|
<Border
|
||||||
x:Name="MainBorder"
|
x:Name="MainBorder"
|
||||||
CornerRadius="8"
|
CornerRadius="8"
|
||||||
@@ -29,57 +29,136 @@
|
|||||||
Opacity="0.3"
|
Opacity="0.3"
|
||||||
BlurRadius="8" />
|
BlurRadius="8" />
|
||||||
</Border.Effect>
|
</Border.Effect>
|
||||||
|
|
||||||
<Grid Margin="10,8">
|
|
||||||
<StackPanel x:Name="SpeedPanel" Orientation="Vertical">
|
|
||||||
<!-- Upload Speed -->
|
|
||||||
<Grid x:Name="UploadGrid">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock
|
|
||||||
Grid.Column="0"
|
|
||||||
Text="↑"
|
|
||||||
Foreground="#FF6B6B"
|
|
||||||
FontSize="12"
|
|
||||||
FontWeight="Bold"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Margin="0,0,6,0" />
|
|
||||||
<TextBlock
|
|
||||||
x:Name="UploadSpeedText"
|
|
||||||
Grid.Column="1"
|
|
||||||
Text="{Binding UploadSpeed}"
|
|
||||||
FontSize="12"
|
|
||||||
FontWeight="SemiBold"
|
|
||||||
Foreground="#333333"
|
|
||||||
VerticalAlignment="Center" />
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- Download Speed -->
|
<Grid Margin="10,8">
|
||||||
<Grid x:Name="DownloadGrid" Margin="0,5,0,0">
|
<StackPanel x:Name="MainPanel" Orientation="Vertical">
|
||||||
<Grid.ColumnDefinitions>
|
<!-- Global Speed Panel -->
|
||||||
<ColumnDefinition Width="Auto" />
|
<StackPanel x:Name="SpeedPanel" Orientation="Vertical">
|
||||||
<ColumnDefinition Width="*" />
|
<!-- Upload Speed -->
|
||||||
</Grid.ColumnDefinitions>
|
<Grid x:Name="UploadGrid">
|
||||||
<TextBlock
|
<Grid.ColumnDefinitions>
|
||||||
Grid.Column="0"
|
<ColumnDefinition Width="Auto" />
|
||||||
Text="↓"
|
<ColumnDefinition Width="*" />
|
||||||
Foreground="#4ECDC4"
|
</Grid.ColumnDefinitions>
|
||||||
FontSize="12"
|
<TextBlock
|
||||||
FontWeight="Bold"
|
Grid.Column="0"
|
||||||
VerticalAlignment="Center"
|
Text="↑"
|
||||||
Margin="0,0,6,0" />
|
Foreground="#FF6B6B"
|
||||||
<TextBlock
|
FontSize="12"
|
||||||
x:Name="DownloadSpeedText"
|
FontWeight="Bold"
|
||||||
Grid.Column="1"
|
VerticalAlignment="Center"
|
||||||
Text="{Binding DownloadSpeed}"
|
Margin="0,0,6,0" />
|
||||||
FontSize="12"
|
<TextBlock
|
||||||
FontWeight="SemiBold"
|
x:Name="UploadSpeedText"
|
||||||
Foreground="#333333"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center" />
|
Text="{Binding UploadSpeed}"
|
||||||
</Grid>
|
FontSize="12"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="#333333"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Download Speed -->
|
||||||
|
<Grid x:Name="DownloadGrid" Margin="0,5,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
Text="↓"
|
||||||
|
Foreground="#4ECDC4"
|
||||||
|
FontSize="12"
|
||||||
|
FontWeight="Bold"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Margin="0,0,6,0" />
|
||||||
|
<TextBlock
|
||||||
|
x:Name="DownloadSpeedText"
|
||||||
|
Grid.Column="1"
|
||||||
|
Text="{Binding DownloadSpeed}"
|
||||||
|
FontSize="12"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="#333333"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- Network Top List Panel -->
|
||||||
|
<StackPanel x:Name="TopListPanel" Orientation="Vertical" Margin="0,8,0,0"
|
||||||
|
Visibility="{Binding TopListVisibility}">
|
||||||
|
<!-- Separator Line -->
|
||||||
|
<Border Height="1" Background="#E0E0E0" Margin="0,0,0,6" />
|
||||||
|
|
||||||
|
<!-- Top List Items -->
|
||||||
|
<ItemsControl x:Name="TopListItems" ItemsSource="{Binding TopProcesses}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid Margin="0,2,0,2">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="16" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" MinWidth="40" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- App Icon -->
|
||||||
|
<Image Grid.Column="0" Width="12" Height="12"
|
||||||
|
Source="{Binding IconSource}"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<!-- App Name -->
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="{Binding ProcessName}"
|
||||||
|
FontSize="10"
|
||||||
|
FontWeight="Normal"
|
||||||
|
Foreground="#666666"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
MaxWidth="60"
|
||||||
|
TextTrimming="CharacterEllipsis"
|
||||||
|
Margin="4,0,8,0" />
|
||||||
|
|
||||||
|
<!-- Upload Speed -->
|
||||||
|
<Grid Grid.Column="3">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Grid.Column="0" Text="↑"
|
||||||
|
Foreground="#FF6B6B" FontSize="9"
|
||||||
|
VerticalAlignment="Center" Margin="0,0,2,0" />
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="{Binding FormattedUploadSpeed}"
|
||||||
|
FontSize="9" FontWeight="Normal"
|
||||||
|
Foreground="#666666"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
MinWidth="35"
|
||||||
|
TextAlignment="Right" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Download Speed -->
|
||||||
|
<Grid Grid.Column="4" Margin="8,0,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Grid.Column="0" Text="↓"
|
||||||
|
Foreground="#4ECDC4" FontSize="9"
|
||||||
|
VerticalAlignment="Center" Margin="0,0,2,0" />
|
||||||
|
<TextBlock Grid.Column="1"
|
||||||
|
Text="{Binding FormattedDownloadSpeed}"
|
||||||
|
FontSize="9" FontWeight="Normal"
|
||||||
|
Foreground="#666666"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
MinWidth="35"
|
||||||
|
TextAlignment="Right" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@@ -7,6 +7,7 @@ using System.Windows.Interop;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Shell.Views;
|
using Shell.Views;
|
||||||
|
using Common.Logger;
|
||||||
|
|
||||||
namespace Shell.Utils;
|
namespace Shell.Utils;
|
||||||
|
|
||||||
@@ -18,6 +19,8 @@ public class TrayIconManager : IDisposable
|
|||||||
private DispatcherTimer _clickTimer;
|
private DispatcherTimer _clickTimer;
|
||||||
private bool _isDoubleClick = false;
|
private bool _isDoubleClick = false;
|
||||||
private DispatcherTimer _menuCloseTimer;
|
private DispatcherTimer _menuCloseTimer;
|
||||||
|
private bool _lastLeftButtonState = false;
|
||||||
|
private bool _lastRightButtonState = false;
|
||||||
|
|
||||||
// Win32 API 用于获取鼠标位置和显示器信息
|
// Win32 API 用于获取鼠标位置和显示器信息
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
@@ -29,6 +32,13 @@ public class TrayIconManager : IDisposable
|
|||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
|
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
|
||||||
|
|
||||||
|
// 添加获取鼠标按键状态的API
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern short GetAsyncKeyState(int vKey);
|
||||||
|
|
||||||
|
private const int VK_LBUTTON = 0x01;
|
||||||
|
private const int VK_RBUTTON = 0x02;
|
||||||
|
|
||||||
// 添加DPI相关API
|
// 添加DPI相关API
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
private static extern uint GetDpiForWindow(IntPtr hwnd);
|
private static extern uint GetDpiForWindow(IntPtr hwnd);
|
||||||
@@ -108,16 +118,21 @@ public class TrayIconManager : IDisposable
|
|||||||
_contextMenu = new ContextMenu();
|
_contextMenu = new ContextMenu();
|
||||||
|
|
||||||
// 添加失去焦点时关闭事件
|
// 添加失去焦点时关闭事件
|
||||||
_contextMenu.Closed += (s, e) =>
|
_contextMenu.Closed += (s, e) => { };
|
||||||
{
|
|
||||||
/* 菜单关闭 */
|
|
||||||
};
|
|
||||||
_contextMenu.LostFocus += (s, e) =>
|
_contextMenu.LostFocus += (s, e) =>
|
||||||
{
|
{
|
||||||
if (_contextMenu != null)
|
// 暂时禁用自动关闭来调试问题
|
||||||
_contextMenu.IsOpen = false;
|
// if (_contextMenu != null)
|
||||||
|
// _contextMenu.IsOpen = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 添加更多事件监听来调试
|
||||||
|
_contextMenu.Opened += (s, e) => { };
|
||||||
|
|
||||||
|
_contextMenu.MouseEnter += (s, e) => { };
|
||||||
|
|
||||||
|
_contextMenu.MouseLeave += (s, e) => { };
|
||||||
|
|
||||||
// 展示主窗口(可勾选)
|
// 展示主窗口(可勾选)
|
||||||
var showMainWindowItem = new MenuItem
|
var showMainWindowItem = new MenuItem
|
||||||
{
|
{
|
||||||
@@ -282,8 +297,13 @@ public class TrayIconManager : IDisposable
|
|||||||
_contextMenu.Placement = PlacementMode.MousePoint;
|
_contextMenu.Placement = PlacementMode.MousePoint;
|
||||||
_contextMenu.StaysOpen = true; // 保持打开,我们手动控制关闭
|
_contextMenu.StaysOpen = true; // 保持打开,我们手动控制关闭
|
||||||
|
|
||||||
|
// 禁用默认的关闭行为
|
||||||
_contextMenu.IsOpen = true;
|
_contextMenu.IsOpen = true;
|
||||||
|
|
||||||
|
// 强制设置,确保菜单不会因为失去焦点而关闭
|
||||||
|
_contextMenu.UpdateLayout();
|
||||||
|
|
||||||
|
|
||||||
// 启动定时器来检测点击外部
|
// 启动定时器来检测点击外部
|
||||||
StartMenuCloseTimer();
|
StartMenuCloseTimer();
|
||||||
}
|
}
|
||||||
@@ -297,9 +317,10 @@ public class TrayIconManager : IDisposable
|
|||||||
|
|
||||||
_menuCloseTimer = new DispatcherTimer
|
_menuCloseTimer = new DispatcherTimer
|
||||||
{
|
{
|
||||||
Interval = TimeSpan.FromMilliseconds(100) // 每100ms检查一次
|
Interval = TimeSpan.FromMilliseconds(50) // 改为每50ms检查一次,提高响应速度
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
_menuCloseTimer.Tick += (s, e) =>
|
_menuCloseTimer.Tick += (s, e) =>
|
||||||
{
|
{
|
||||||
if (!_contextMenu.IsOpen)
|
if (!_contextMenu.IsOpen)
|
||||||
@@ -317,12 +338,23 @@ public class TrayIconManager : IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有鼠标按键按下
|
// 使用Win32 API检测鼠标按键状态变化
|
||||||
if (System.Windows.Input.Mouse.LeftButton == System.Windows.Input.MouseButtonState.Pressed ||
|
bool currentLeftState = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
|
||||||
System.Windows.Input.Mouse.RightButton == System.Windows.Input.MouseButtonState.Pressed)
|
bool currentRightState = (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0;
|
||||||
|
|
||||||
|
// 检测按键从未按下到按下的状态变化(按下事件)
|
||||||
|
bool leftButtonPressed = currentLeftState && !_lastLeftButtonState;
|
||||||
|
bool rightButtonPressed = currentRightState && !_lastRightButtonState;
|
||||||
|
|
||||||
|
_lastLeftButtonState = currentLeftState;
|
||||||
|
_lastRightButtonState = currentRightState;
|
||||||
|
|
||||||
|
if (leftButtonPressed || rightButtonPressed)
|
||||||
{
|
{
|
||||||
// 如果鼠标不在菜单区域内且有按键按下,则关闭菜单
|
// 如果鼠标不在菜单区域内且有按键按下,则关闭菜单
|
||||||
if (!IsMouseOverContextMenu())
|
bool isMouseOver = IsMouseOverContextMenu();
|
||||||
|
|
||||||
|
if (!isMouseOver)
|
||||||
{
|
{
|
||||||
if (_contextMenu != null)
|
if (_contextMenu != null)
|
||||||
_contextMenu.IsOpen = false;
|
_contextMenu.IsOpen = false;
|
||||||
@@ -332,13 +364,20 @@ public class TrayIconManager : IDisposable
|
|||||||
};
|
};
|
||||||
|
|
||||||
_menuCloseTimer.Start();
|
_menuCloseTimer.Start();
|
||||||
|
|
||||||
|
// 重置按键状态,避免误检测
|
||||||
|
_lastLeftButtonState = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
|
||||||
|
_lastRightButtonState = (GetAsyncKeyState(VK_RBUTTON) & 0x8000) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsMouseOverContextMenu()
|
private bool IsMouseOverContextMenu()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_contextMenu == null || !_contextMenu.IsOpen) return false;
|
if (_contextMenu == null || !_contextMenu.IsOpen)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 获取屏幕上的鼠标位置
|
// 获取屏幕上的鼠标位置
|
||||||
GetCursorPos(out POINT screenPoint);
|
GetCursorPos(out POINT screenPoint);
|
||||||
@@ -346,10 +385,17 @@ public class TrayIconManager : IDisposable
|
|||||||
|
|
||||||
// 获取菜单的屏幕位置和大小
|
// 获取菜单的屏幕位置和大小
|
||||||
var contextMenuElement = _contextMenu as FrameworkElement;
|
var contextMenuElement = _contextMenu as FrameworkElement;
|
||||||
if (contextMenuElement == null) return false;
|
if (contextMenuElement == null)
|
||||||
|
{
|
||||||
|
return true; // 改为返回true,避免意外关闭
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var source = PresentationSource.FromVisual(contextMenuElement);
|
var source = PresentationSource.FromVisual(contextMenuElement);
|
||||||
if (source == null) return false;
|
if (source == null)
|
||||||
|
{
|
||||||
|
return true; // 改为返回true,避免意外关闭
|
||||||
|
}
|
||||||
|
|
||||||
// 获取菜单的屏幕边界
|
// 获取菜单的屏幕边界
|
||||||
var menuTopLeft = contextMenuElement.PointToScreen(new System.Windows.Point(0, 0));
|
var menuTopLeft = contextMenuElement.PointToScreen(new System.Windows.Point(0, 0));
|
||||||
@@ -357,14 +403,25 @@ public class TrayIconManager : IDisposable
|
|||||||
contextMenuElement.PointToScreen(new System.Windows.Point(contextMenuElement.ActualWidth,
|
contextMenuElement.PointToScreen(new System.Windows.Point(contextMenuElement.ActualWidth,
|
||||||
contextMenuElement.ActualHeight));
|
contextMenuElement.ActualHeight));
|
||||||
|
|
||||||
var menuBounds = new Rect(menuTopLeft, menuBottomRight);
|
|
||||||
|
|
||||||
return menuBounds.Contains(screenPosition);
|
// 添加一些边距,让鼠标检测区域稍微大一点,避免意外关闭
|
||||||
|
var margin = 5;
|
||||||
|
var menuBounds = new Rect(
|
||||||
|
menuTopLeft.X - margin,
|
||||||
|
menuTopLeft.Y - margin,
|
||||||
|
menuBottomRight.X - menuTopLeft.X + (margin * 2),
|
||||||
|
menuBottomRight.Y - menuTopLeft.Y + (margin * 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
bool contains = menuBounds.Contains(screenPosition);
|
||||||
|
|
||||||
|
return contains;
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// 如果检测失败,假设鼠标不在菜单上,这样会更安全
|
// 如果检测失败,假设鼠标在菜单上,避免意外关闭
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Common.Logger;
|
using Common.Logger;
|
||||||
using Common.Utils;
|
using Common.Utils;
|
||||||
|
using Utils.ETW.Services;
|
||||||
|
using Shell.Models;
|
||||||
|
using Data;
|
||||||
|
using Utils.ETW.Models;
|
||||||
|
|
||||||
namespace Shell.ViewModel;
|
namespace Shell.ViewModel;
|
||||||
|
|
||||||
@@ -90,6 +94,31 @@ public class NetworkMonitorViewModel : INotifyPropertyChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Top榜相关属性
|
||||||
|
private ObservableCollection<ProcessNetworkStatsViewModel> _topProcesses = new();
|
||||||
|
|
||||||
|
public ObservableCollection<ProcessNetworkStatsViewModel> TopProcesses
|
||||||
|
{
|
||||||
|
get => _topProcesses;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_topProcesses = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private System.Windows.Visibility _topListVisibility = System.Windows.Visibility.Collapsed;
|
||||||
|
|
||||||
|
public System.Windows.Visibility TopListVisibility
|
||||||
|
{
|
||||||
|
get => _topListVisibility;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_topListVisibility = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Commands
|
#region Commands
|
||||||
@@ -126,6 +155,7 @@ public class NetworkMonitorViewModel : INotifyPropertyChanged
|
|||||||
|
|
||||||
// 初始化数据
|
// 初始化数据
|
||||||
LoadNetworkInterfaces();
|
LoadNetworkInterfaces();
|
||||||
|
LoadTopListSettings();
|
||||||
_updateTimer.Start();
|
_updateTimer.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -369,6 +399,9 @@ public class NetworkMonitorViewModel : INotifyPropertyChanged
|
|||||||
DownloadSpeed = speed.DownloadSpeedText;
|
DownloadSpeed = speed.DownloadSpeedText;
|
||||||
UploadSpeed = speed.UploadSpeedText;
|
UploadSpeed = speed.UploadSpeedText;
|
||||||
TotalSpeed = speed.TotalSpeedText;
|
TotalSpeed = speed.TotalSpeedText;
|
||||||
|
|
||||||
|
// 更新Top榜
|
||||||
|
UpdateTopList();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -403,6 +436,145 @@ public class NetworkMonitorViewModel : INotifyPropertyChanged
|
|||||||
StatusText = "接口列表已刷新";
|
StatusText = "接口列表已刷新";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载Top榜设置
|
||||||
|
/// </summary>
|
||||||
|
private async void LoadTopListSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 从数据库加载设置
|
||||||
|
var settings = await DatabaseManager.GetUserSettingsAsync();
|
||||||
|
var netViewSettings = NetViewSettings.Instance;
|
||||||
|
|
||||||
|
// 同步设置
|
||||||
|
netViewSettings.ShowNetworkTopList = settings.ShowNetworkTopList;
|
||||||
|
netViewSettings.NetworkTopListCount = settings.NetworkTopListCount;
|
||||||
|
|
||||||
|
// 更新可见性
|
||||||
|
UpdateTopListVisibility();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error4Ctx($"加载Top榜设置失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新Top榜可见性
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateTopListVisibility()
|
||||||
|
{
|
||||||
|
var settings = NetViewSettings.Instance;
|
||||||
|
var shouldShow = settings.ShowNetworkTopList && settings.IsTopListAvailable;
|
||||||
|
TopListVisibility = shouldShow ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新Top榜数据
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateTopList()
|
||||||
|
{
|
||||||
|
if (_isDesignMode)
|
||||||
|
{
|
||||||
|
UpdateDesignTimeTopList();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = NetViewSettings.Instance;
|
||||||
|
if (!settings.ShowNetworkTopList || !settings.IsTopListAvailable)
|
||||||
|
{
|
||||||
|
TopListVisibility = System.Windows.Visibility.Collapsed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新NetworkTopListManager的统计数据
|
||||||
|
NetworkTopListManager.Instance.UpdateAllProcessStats();
|
||||||
|
|
||||||
|
// 获取Top榜数据
|
||||||
|
var topList = NetworkTopListManager.Instance.GetTopList(settings.NetworkTopListCount);
|
||||||
|
|
||||||
|
if (topList.HasData)
|
||||||
|
{
|
||||||
|
// 更新现有项目或添加新项目
|
||||||
|
var newViewModels = topList.TopProcesses.Select(stats =>
|
||||||
|
{
|
||||||
|
var existing = TopProcesses.FirstOrDefault(vm => vm.ProcessId == stats.ProcessId);
|
||||||
|
if (existing != null)
|
||||||
|
{
|
||||||
|
existing.UpdateStats(stats);
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ProcessNetworkStatsViewModel(stats);
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// 更新集合
|
||||||
|
TopProcesses.Clear();
|
||||||
|
foreach (var vm in newViewModels)
|
||||||
|
{
|
||||||
|
TopProcesses.Add(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
TopListVisibility = System.Windows.Visibility.Visible;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TopProcesses.Clear();
|
||||||
|
TopListVisibility = System.Windows.Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error4Ctx($"更新Top榜时发生错误: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设计时Top榜数据
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateDesignTimeTopList()
|
||||||
|
{
|
||||||
|
if (TopProcesses.Count == 0)
|
||||||
|
{
|
||||||
|
// 添加一些假数据用于设计时预览
|
||||||
|
var fakeStats = new[]
|
||||||
|
{
|
||||||
|
new ProcessNetworkStats
|
||||||
|
{
|
||||||
|
ProcessId = 1234,
|
||||||
|
ProcessName = "chrome",
|
||||||
|
CurrentUploadSpeed = 1024 * 500, // 500 KB/s
|
||||||
|
CurrentDownloadSpeed = 1024 * 1024 * 15.5, // 15.5 MB/s
|
||||||
|
},
|
||||||
|
new ProcessNetworkStats
|
||||||
|
{
|
||||||
|
ProcessId = 5678,
|
||||||
|
ProcessName = "firefox",
|
||||||
|
CurrentUploadSpeed = 1024 * 200, // 200 KB/s
|
||||||
|
CurrentDownloadSpeed = 1024 * 1024 * 8.2, // 8.2 MB/s
|
||||||
|
},
|
||||||
|
new ProcessNetworkStats
|
||||||
|
{
|
||||||
|
ProcessId = 9012,
|
||||||
|
ProcessName = "steam",
|
||||||
|
CurrentUploadSpeed = 1024 * 50, // 50 KB/s
|
||||||
|
CurrentDownloadSpeed = 1024 * 1024 * 5.1, // 5.1 MB/s
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TopProcesses.Clear();
|
||||||
|
foreach (var stats in fakeStats)
|
||||||
|
{
|
||||||
|
TopProcesses.Add(new ProcessNetworkStatsViewModel(stats));
|
||||||
|
}
|
||||||
|
|
||||||
|
TopListVisibility = System.Windows.Visibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 测试用的异步方法
|
// 测试用的异步方法
|
||||||
private static async Task TestNetworkMethods()
|
private static async Task TestNetworkMethods()
|
||||||
{
|
{
|
||||||
@@ -480,4 +652,4 @@ public class RelayCommand : ICommand
|
|||||||
public void Execute(object parameter) => _execute();
|
public void Execute(object parameter) => _execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Utils.ETW.Models;
|
||||||
|
|
||||||
|
namespace Shell.ViewModel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 进程网络统计的ViewModel
|
||||||
|
/// 用于在UI中显示Top榜信息
|
||||||
|
/// </summary>
|
||||||
|
public class ProcessNetworkStatsViewModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private ProcessNetworkStats _stats;
|
||||||
|
|
||||||
|
public ProcessNetworkStatsViewModel(ProcessNetworkStats stats)
|
||||||
|
{
|
||||||
|
_stats = stats;
|
||||||
|
LoadIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 进程ID
|
||||||
|
/// </summary>
|
||||||
|
public int ProcessId => _stats.ProcessId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 进程名称
|
||||||
|
/// </summary>
|
||||||
|
public string ProcessName => _stats.ProcessName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化的上传速度
|
||||||
|
/// </summary>
|
||||||
|
public string FormattedUploadSpeed => _stats.FormattedUploadSpeed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化的下载速度
|
||||||
|
/// </summary>
|
||||||
|
public string FormattedDownloadSpeed => _stats.FormattedDownloadSpeed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化的总速度
|
||||||
|
/// </summary>
|
||||||
|
public string FormattedTotalSpeed => _stats.FormattedTotalSpeed;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 总速度(用于排序)
|
||||||
|
/// </summary>
|
||||||
|
public double TotalSpeed => _stats.TotalSpeed;
|
||||||
|
|
||||||
|
private BitmapImage? _iconSource;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图标源
|
||||||
|
/// </summary>
|
||||||
|
public BitmapImage? IconSource
|
||||||
|
{
|
||||||
|
get => _iconSource;
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
_iconSource = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新统计数据
|
||||||
|
/// </summary>
|
||||||
|
public void UpdateStats(ProcessNetworkStats newStats)
|
||||||
|
{
|
||||||
|
_stats = newStats;
|
||||||
|
OnPropertyChanged(nameof(ProcessName));
|
||||||
|
OnPropertyChanged(nameof(FormattedUploadSpeed));
|
||||||
|
OnPropertyChanged(nameof(FormattedDownloadSpeed));
|
||||||
|
OnPropertyChanged(nameof(FormattedTotalSpeed));
|
||||||
|
OnPropertyChanged(nameof(TotalSpeed));
|
||||||
|
|
||||||
|
// 如果图标还未加载,尝试重新加载
|
||||||
|
if (_iconSource == null)
|
||||||
|
{
|
||||||
|
LoadIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载进程图标
|
||||||
|
/// </summary>
|
||||||
|
private void LoadIcon()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_stats.ApplicationInfo?.ProgramInfo?.IconBase64 != null)
|
||||||
|
{
|
||||||
|
var iconBytes = Convert.FromBase64String(_stats.ApplicationInfo.ProgramInfo.IconBase64);
|
||||||
|
var bitmap = new BitmapImage();
|
||||||
|
bitmap.BeginInit();
|
||||||
|
bitmap.StreamSource = new System.IO.MemoryStream(iconBytes);
|
||||||
|
bitmap.DecodePixelWidth = 12; // 优化性能,直接解码为所需大小
|
||||||
|
bitmap.DecodePixelHeight = 12;
|
||||||
|
bitmap.CacheOption = BitmapCacheOption.OnLoad; // 缓存以提高性能
|
||||||
|
bitmap.EndInit();
|
||||||
|
bitmap.Freeze(); // 冻结以允许跨线程访问
|
||||||
|
|
||||||
|
IconSource = bitmap;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 使用默认图标或留空
|
||||||
|
IconSource = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// 如果图标加载失败,使用null(UI会显示默认外观)
|
||||||
|
IconSource = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
|
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,11 +6,11 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="NetVizor - 设置"
|
Title="NetVizor - 设置"
|
||||||
Height="480"
|
Height="620"
|
||||||
Width="470"
|
Width="470"
|
||||||
MinHeight="480"
|
MinHeight="620"
|
||||||
MinWidth="470"
|
MinWidth="470"
|
||||||
MaxHeight="480"
|
MaxHeight="620"
|
||||||
MaxWidth="470"
|
MaxWidth="470"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
ResizeMode="NoResize">
|
ResizeMode="NoResize">
|
||||||
@@ -108,14 +108,30 @@
|
|||||||
|
|
||||||
<!-- 显示单位 -->
|
<!-- 显示单位 -->
|
||||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="显示选项" VerticalAlignment="Center" />
|
<TextBlock Grid.Row="4" Grid.Column="0" Text="显示选项" VerticalAlignment="Center" />
|
||||||
<CheckBox Grid.Row="4" Grid.Column="1" x:Name="ShowUnitCheckBox" Content="显示单位"
|
<StackPanel Grid.Row="4" Grid.Column="1">
|
||||||
IsChecked="True" Checked="ShowUnitCheckBox_Changed"
|
<CheckBox x:Name="ShowUnitCheckBox" Content="显示单位"
|
||||||
Unchecked="ShowUnitCheckBox_Changed" />
|
IsChecked="True" Checked="ShowUnitCheckBox_Changed"
|
||||||
|
Unchecked="ShowUnitCheckBox_Changed" />
|
||||||
|
<CheckBox x:Name="ShowTopListCheckBox" Content="显示网速排行榜" Margin="0,4,0,0"
|
||||||
|
IsChecked="False" Checked="ShowTopListCheckBox_Changed"
|
||||||
|
Unchecked="ShowTopListCheckBox_Changed" IsEnabled="False" />
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="0,4,0,0">
|
||||||
|
<TextBlock Text="排行榜数量:" VerticalAlignment="Center" Margin="0,0,8,0" />
|
||||||
|
<ComboBox x:Name="TopListCountComboBox" Width="80"
|
||||||
|
SelectionChanged="TopListCountComboBox_SelectionChanged" IsEnabled="False">
|
||||||
|
<ComboBoxItem Content="1" Tag="1" />
|
||||||
|
<ComboBoxItem Content="2" Tag="2" />
|
||||||
|
<ComboBoxItem Content="3" Tag="3" IsSelected="True" />
|
||||||
|
<ComboBoxItem Content="4" Tag="4" />
|
||||||
|
<ComboBoxItem Content="5" Tag="5" />
|
||||||
|
</ComboBox>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<!-- 交互 -->
|
<!-- 交互 -->
|
||||||
<TextBlock Text="交互" FontSize="14" FontWeight="Bold" Margin="0,0,0,12" />
|
<TextBlock Text="交互" FontSize="14" FontWeight="Bold" Margin="0,0,0,12" />
|
||||||
<Grid>
|
<Grid Margin="0,0,0,16">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="80" />
|
<ColumnDefinition Width="80" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
@@ -129,6 +145,56 @@
|
|||||||
<ComboBoxItem Content="打开设置" Tag="Settings" />
|
<ComboBoxItem Content="打开设置" Tag="Settings" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<!-- 窗口行为 -->
|
||||||
|
<TextBlock Text="窗口行为" FontSize="14" FontWeight="Bold" Margin="0,0,0,12" />
|
||||||
|
<Grid Margin="0,0,0,16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="8" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="8" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="8" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="8" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="12" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<!-- 始终置顶 -->
|
||||||
|
<CheckBox Grid.Row="0" x:Name="TopmostCheckBox" Content="始终置顶"
|
||||||
|
IsChecked="True" Checked="TopmostCheckBox_Changed"
|
||||||
|
Unchecked="TopmostCheckBox_Changed" />
|
||||||
|
|
||||||
|
<!-- 锁定窗口位置 -->
|
||||||
|
<CheckBox Grid.Row="2" x:Name="LockPositionCheckBox" Content="锁定窗口位置"
|
||||||
|
IsChecked="False" Checked="LockPositionCheckBox_Changed"
|
||||||
|
Unchecked="LockPositionCheckBox_Changed" />
|
||||||
|
|
||||||
|
<!-- 启用点击穿透 -->
|
||||||
|
<CheckBox Grid.Row="4" x:Name="ClickThroughCheckBox" Content="启用点击穿透"
|
||||||
|
IsChecked="False" Checked="ClickThroughCheckBox_Changed"
|
||||||
|
Unchecked="ClickThroughCheckBox_Changed" />
|
||||||
|
|
||||||
|
<!-- 不能超出屏幕 -->
|
||||||
|
<CheckBox Grid.Row="6" x:Name="SnapToScreenCheckBox" Content="不能超出屏幕"
|
||||||
|
IsChecked="False" Checked="SnapToScreenCheckBox_Changed"
|
||||||
|
Unchecked="SnapToScreenCheckBox_Changed" />
|
||||||
|
|
||||||
|
<!-- 显示详细信息 -->
|
||||||
|
<CheckBox Grid.Row="8" x:Name="ShowDetailedInfoCheckBox" Content="显示详细信息"
|
||||||
|
IsChecked="False" Checked="ShowDetailedInfoCheckBox_Changed"
|
||||||
|
Unchecked="ShowDetailedInfoCheckBox_Changed" />
|
||||||
|
|
||||||
|
<!-- 重置窗口位置按钮 -->
|
||||||
|
<Button Grid.Row="10" HorizontalAlignment="Left" Content="重置窗口位置"
|
||||||
|
Click="ResetWindowPosition_Click" Padding="12,6" MinWidth="100" />
|
||||||
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- 右侧预览区 -->
|
<!-- 右侧预览区 -->
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public partial class SettingsWindow : Window
|
|||||||
{
|
{
|
||||||
_instance = new SettingsWindow();
|
_instance = new SettingsWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,10 +32,10 @@ public partial class SettingsWindow : Window
|
|||||||
_settings = NetViewSettings.Instance;
|
_settings = NetViewSettings.Instance;
|
||||||
this.Loaded += SettingsWindow_Loaded;
|
this.Loaded += SettingsWindow_Loaded;
|
||||||
this.Closing += SettingsWindow_Closing;
|
this.Closing += SettingsWindow_Closing;
|
||||||
|
|
||||||
LoadCurrentSettings();
|
LoadCurrentSettings();
|
||||||
UpdatePreview();
|
UpdatePreview();
|
||||||
|
|
||||||
Log.Info("SettingsWindow 初始化");
|
Log.Info("SettingsWindow 初始化");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +83,19 @@ public partial class SettingsWindow : Window
|
|||||||
VerticalLayoutRadio.IsChecked = _settings.LayoutDirection == LayoutDirection.Vertical;
|
VerticalLayoutRadio.IsChecked = _settings.LayoutDirection == LayoutDirection.Vertical;
|
||||||
HorizontalLayoutRadio.IsChecked = _settings.LayoutDirection == LayoutDirection.Horizontal;
|
HorizontalLayoutRadio.IsChecked = _settings.LayoutDirection == LayoutDirection.Horizontal;
|
||||||
|
|
||||||
|
// 设置网速Top榜
|
||||||
|
ShowTopListCheckBox.IsChecked = _settings.ShowNetworkTopList;
|
||||||
|
foreach (ComboBoxItem item in TopListCountComboBox.Items)
|
||||||
|
{
|
||||||
|
if (item.Tag.ToString() == _settings.NetworkTopListCount.ToString())
|
||||||
|
{
|
||||||
|
TopListCountComboBox.SelectedItem = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateTopListAvailability();
|
||||||
|
|
||||||
// 设置双击动作
|
// 设置双击动作
|
||||||
foreach (ComboBoxItem item in DoubleClickActionComboBox.Items)
|
foreach (ComboBoxItem item in DoubleClickActionComboBox.Items)
|
||||||
{
|
{
|
||||||
@@ -92,6 +106,13 @@ public partial class SettingsWindow : Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置窗口行为选项
|
||||||
|
TopmostCheckBox.IsChecked = _settings.Topmost;
|
||||||
|
LockPositionCheckBox.IsChecked = _settings.LockPosition;
|
||||||
|
ClickThroughCheckBox.IsChecked = _settings.ClickThrough;
|
||||||
|
SnapToScreenCheckBox.IsChecked = _settings.SnapToScreen;
|
||||||
|
ShowDetailedInfoCheckBox.IsChecked = _settings.ShowDetailedInfo;
|
||||||
|
|
||||||
UpdateColorButtons();
|
UpdateColorButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,10 +120,13 @@ public partial class SettingsWindow : Window
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var textColor = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(_settings.TextColor);
|
var textColor =
|
||||||
|
(System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(_settings.TextColor);
|
||||||
TextColorButton.Background = new SolidColorBrush(textColor);
|
TextColorButton.Background = new SolidColorBrush(textColor);
|
||||||
|
|
||||||
var backgroundColor = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(_settings.BackgroundColor);
|
var backgroundColor =
|
||||||
|
(System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(_settings
|
||||||
|
.BackgroundColor);
|
||||||
BackgroundColorButton.Background = new SolidColorBrush(backgroundColor);
|
BackgroundColorButton.Background = new SolidColorBrush(backgroundColor);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -116,17 +140,22 @@ public partial class SettingsWindow : Window
|
|||||||
var dialog = new System.Windows.Forms.ColorDialog();
|
var dialog = new System.Windows.Forms.ColorDialog();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var currentColor = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(TextColorBox.Text);
|
var currentColor =
|
||||||
dialog.Color = System.Drawing.Color.FromArgb(currentColor.A, currentColor.R, currentColor.G, currentColor.B);
|
(System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(TextColorBox.Text);
|
||||||
|
dialog.Color =
|
||||||
|
System.Drawing.Color.FromArgb(currentColor.A, currentColor.R, currentColor.G, currentColor.B);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
|
|
||||||
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||||
{
|
{
|
||||||
var color = dialog.Color;
|
var color = dialog.Color;
|
||||||
var colorString = $"#{color.R:X2}{color.G:X2}{color.B:X2}";
|
var colorString = $"#{color.R:X2}{color.G:X2}{color.B:X2}";
|
||||||
TextColorBox.Text = colorString;
|
TextColorBox.Text = colorString;
|
||||||
TextColorButton.Background = new SolidColorBrush(System.Windows.Media.Color.FromRgb(color.R, color.G, color.B));
|
TextColorButton.Background =
|
||||||
|
new SolidColorBrush(System.Windows.Media.Color.FromRgb(color.R, color.G, color.B));
|
||||||
UpdatePreview();
|
UpdatePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,10 +165,14 @@ public partial class SettingsWindow : Window
|
|||||||
var dialog = new System.Windows.Forms.ColorDialog();
|
var dialog = new System.Windows.Forms.ColorDialog();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var currentColor = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(BackgroundColorBox.Text);
|
var currentColor =
|
||||||
|
(System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(BackgroundColorBox
|
||||||
|
.Text);
|
||||||
dialog.Color = System.Drawing.Color.FromArgb(currentColor.R, currentColor.G, currentColor.B);
|
dialog.Color = System.Drawing.Color.FromArgb(currentColor.R, currentColor.G, currentColor.B);
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
|
||||||
{
|
{
|
||||||
@@ -148,7 +181,8 @@ public partial class SettingsWindow : Window
|
|||||||
var alpha = (byte)(OpacitySlider.Value / 100.0 * 255);
|
var alpha = (byte)(OpacitySlider.Value / 100.0 * 255);
|
||||||
var colorString = $"#{alpha:X2}{color.R:X2}{color.G:X2}{color.B:X2}";
|
var colorString = $"#{alpha:X2}{color.R:X2}{color.G:X2}{color.B:X2}";
|
||||||
BackgroundColorBox.Text = colorString;
|
BackgroundColorBox.Text = colorString;
|
||||||
BackgroundColorButton.Background = new SolidColorBrush(System.Windows.Media.Color.FromRgb(color.R, color.G, color.B));
|
BackgroundColorButton.Background =
|
||||||
|
new SolidColorBrush(System.Windows.Media.Color.FromRgb(color.R, color.G, color.B));
|
||||||
UpdatePreview();
|
UpdatePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,7 +192,7 @@ public partial class SettingsWindow : Window
|
|||||||
if (OpacityText != null)
|
if (OpacityText != null)
|
||||||
{
|
{
|
||||||
OpacityText.Text = $"{(int)e.NewValue}%";
|
OpacityText.Text = $"{(int)e.NewValue}%";
|
||||||
|
|
||||||
// 更新背景颜色的透明度
|
// 更新背景颜色的透明度
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -167,12 +201,14 @@ public partial class SettingsWindow : Window
|
|||||||
{
|
{
|
||||||
colorWithoutAlpha = "#" + colorWithoutAlpha.Substring(3); // 移除透明度部分
|
colorWithoutAlpha = "#" + colorWithoutAlpha.Substring(3); // 移除透明度部分
|
||||||
}
|
}
|
||||||
|
|
||||||
var alpha = (byte)(e.NewValue / 100.0 * 255);
|
var alpha = (byte)(e.NewValue / 100.0 * 255);
|
||||||
var color = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(colorWithoutAlpha);
|
var color =
|
||||||
|
(System.Windows.Media.Color)System.Windows.Media.ColorConverter
|
||||||
|
.ConvertFromString(colorWithoutAlpha);
|
||||||
var newColorString = $"#{alpha:X2}{color.R:X2}{color.G:X2}{color.B:X2}";
|
var newColorString = $"#{alpha:X2}{color.R:X2}{color.G:X2}{color.B:X2}";
|
||||||
BackgroundColorBox.Text = newColorString;
|
BackgroundColorBox.Text = newColorString;
|
||||||
|
|
||||||
UpdatePreview();
|
UpdatePreview();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -194,14 +230,87 @@ public partial class SettingsWindow : Window
|
|||||||
|
|
||||||
private void LayoutDirection_Changed(object sender, RoutedEventArgs e)
|
private void LayoutDirection_Changed(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
UpdateTopListAvailability();
|
||||||
UpdatePreview();
|
UpdatePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ShowTopListCheckBox_Changed(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
UpdateTopListCountVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TopListCountComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
// Top榜数量改变不需要预览更新
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTopListAvailability()
|
||||||
|
{
|
||||||
|
if (ShowTopListCheckBox == null || TopListCountComboBox == null) return;
|
||||||
|
|
||||||
|
var isHorizontal = HorizontalLayoutRadio.IsChecked == true;
|
||||||
|
ShowTopListCheckBox.IsEnabled = isHorizontal;
|
||||||
|
|
||||||
|
if (!isHorizontal)
|
||||||
|
{
|
||||||
|
ShowTopListCheckBox.IsChecked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateTopListCountVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateTopListCountVisibility()
|
||||||
|
{
|
||||||
|
if (TopListCountComboBox == null) return;
|
||||||
|
|
||||||
|
var isEnabled = ShowTopListCheckBox.IsEnabled && ShowTopListCheckBox.IsChecked == true;
|
||||||
|
TopListCountComboBox.IsEnabled = isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
private void DoubleClickActionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void DoubleClickActionComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
// 双击动作不需要预览更新
|
// 双击动作不需要预览更新
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void TopmostCheckBox_Changed(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 置顶设置变化,不需要预览更新
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LockPositionCheckBox_Changed(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 锁定位置设置变化,不需要预览更新
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClickThroughCheckBox_Changed(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 点击穿透设置变化,不需要预览更新
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SnapToScreenCheckBox_Changed(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 屏幕边界设置变化,不需要预览更新
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowDetailedInfoCheckBox_Changed(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 详细信息设置变化,不需要预览更新
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetWindowPosition_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// 重置窗口位置 - 这里可以调用 NetView 的重置位置方法
|
||||||
|
try
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show("窗口位置已重置到屏幕中心。", "重置位置", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
Log.Info("窗口位置重置请求");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error4Ctx($"重置窗口位置失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdatePreview()
|
private void UpdatePreview()
|
||||||
{
|
{
|
||||||
if (PreviewBorder == null || PreviewPanel == null) return;
|
if (PreviewBorder == null || PreviewPanel == null) return;
|
||||||
@@ -209,23 +318,27 @@ public partial class SettingsWindow : Window
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 更新背景色
|
// 更新背景色
|
||||||
var backgroundColor = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(BackgroundColorBox.Text);
|
var backgroundColor =
|
||||||
|
(System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(BackgroundColorBox
|
||||||
|
.Text);
|
||||||
PreviewBorder.Background = new SolidColorBrush(backgroundColor);
|
PreviewBorder.Background = new SolidColorBrush(backgroundColor);
|
||||||
|
|
||||||
// 更新文字颜色
|
// 更新文字颜色
|
||||||
var textColor = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(TextColorBox.Text);
|
var textColor =
|
||||||
|
(System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(TextColorBox.Text);
|
||||||
var textBrush = new SolidColorBrush(textColor);
|
var textBrush = new SolidColorBrush(textColor);
|
||||||
PreviewUploadText.Foreground = textBrush;
|
PreviewUploadText.Foreground = textBrush;
|
||||||
PreviewDownloadText.Foreground = textBrush;
|
PreviewDownloadText.Foreground = textBrush;
|
||||||
|
|
||||||
// 更新布局方向
|
// 更新布局方向
|
||||||
PreviewPanel.Orientation = HorizontalLayoutRadio.IsChecked == true ?
|
PreviewPanel.Orientation = HorizontalLayoutRadio.IsChecked == true
|
||||||
System.Windows.Controls.Orientation.Horizontal : System.Windows.Controls.Orientation.Vertical;
|
? System.Windows.Controls.Orientation.Horizontal
|
||||||
|
: System.Windows.Controls.Orientation.Vertical;
|
||||||
|
|
||||||
// 更新显示文本(根据单位设置)
|
// 更新显示文本(根据单位设置)
|
||||||
var showUnit = ShowUnitCheckBox.IsChecked == true;
|
var showUnit = ShowUnitCheckBox.IsChecked == true;
|
||||||
var selectedUnit = ((ComboBoxItem)SpeedUnitComboBox.SelectedItem)?.Tag?.ToString() ?? "Auto";
|
var selectedUnit = ((ComboBoxItem)SpeedUnitComboBox.SelectedItem)?.Tag?.ToString() ?? "Auto";
|
||||||
|
|
||||||
string uploadText, downloadText;
|
string uploadText, downloadText;
|
||||||
switch (selectedUnit)
|
switch (selectedUnit)
|
||||||
{
|
{
|
||||||
@@ -279,12 +392,24 @@ public partial class SettingsWindow : Window
|
|||||||
var selectedUnit = ((ComboBoxItem)SpeedUnitComboBox.SelectedItem)?.Tag?.ToString() ?? "Auto";
|
var selectedUnit = ((ComboBoxItem)SpeedUnitComboBox.SelectedItem)?.Tag?.ToString() ?? "Auto";
|
||||||
_settings.SpeedUnit = Enum.Parse<SpeedUnit>(selectedUnit);
|
_settings.SpeedUnit = Enum.Parse<SpeedUnit>(selectedUnit);
|
||||||
|
|
||||||
_settings.LayoutDirection = HorizontalLayoutRadio.IsChecked == true ?
|
_settings.LayoutDirection = HorizontalLayoutRadio.IsChecked == true
|
||||||
LayoutDirection.Horizontal : LayoutDirection.Vertical;
|
? LayoutDirection.Horizontal
|
||||||
|
: LayoutDirection.Vertical;
|
||||||
|
|
||||||
|
_settings.ShowNetworkTopList = ShowTopListCheckBox.IsChecked == true;
|
||||||
|
var selectedCount = ((ComboBoxItem)TopListCountComboBox.SelectedItem)?.Tag?.ToString() ?? "3";
|
||||||
|
_settings.NetworkTopListCount = int.Parse(selectedCount);
|
||||||
|
|
||||||
var selectedAction = ((ComboBoxItem)DoubleClickActionComboBox.SelectedItem)?.Tag?.ToString() ?? "None";
|
var selectedAction = ((ComboBoxItem)DoubleClickActionComboBox.SelectedItem)?.Tag?.ToString() ?? "None";
|
||||||
_settings.DoubleClickAction = Enum.Parse<DoubleClickAction>(selectedAction);
|
_settings.DoubleClickAction = Enum.Parse<DoubleClickAction>(selectedAction);
|
||||||
|
|
||||||
|
// 应用窗口行为设置
|
||||||
|
_settings.Topmost = TopmostCheckBox.IsChecked == true;
|
||||||
|
_settings.LockPosition = LockPositionCheckBox.IsChecked == true;
|
||||||
|
_settings.ClickThrough = ClickThroughCheckBox.IsChecked == true;
|
||||||
|
_settings.SnapToScreen = SnapToScreenCheckBox.IsChecked == true;
|
||||||
|
_settings.ShowDetailedInfo = ShowDetailedInfoCheckBox.IsChecked == true;
|
||||||
|
|
||||||
// 保存设置
|
// 保存设置
|
||||||
_settings.SaveSettings();
|
_settings.SaveSettings();
|
||||||
|
|
||||||
@@ -300,9 +425,9 @@ public partial class SettingsWindow : Window
|
|||||||
|
|
||||||
private void RestoreDefaults_Click(object sender, RoutedEventArgs e)
|
private void RestoreDefaults_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)
|
||||||
{
|
{
|
||||||
_settings.RestoreDefaults();
|
_settings.RestoreDefaults();
|
||||||
|
|||||||
Reference in new issue
Block a user