A:设置集成数据库
This commit is contained in:
1 parent
c999440973
commit
e35eb3e103
8 files changed
+491
-77
No files matched your search
@@ -0,0 +1,88 @@
|
||||
namespace Data.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 应用网络聚合数据基类
|
||||
/// </summary>
|
||||
public abstract class AppNetworkAggregatedBase
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 软件 ID
|
||||
/// </summary>
|
||||
public string AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总上传字节数
|
||||
/// </summary>
|
||||
public long TotalUploadBytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总下载字节数
|
||||
/// </summary>
|
||||
public long TotalDownloadBytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接数量
|
||||
/// </summary>
|
||||
public int ConnectionCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 唯一远程IP数量
|
||||
/// </summary>
|
||||
public int UniqueRemoteIPs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 唯一远程端口数量
|
||||
/// </summary>
|
||||
public int UniqueRemotePorts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间戳
|
||||
/// </summary>
|
||||
public long CreatedTimestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用网络小时聚合数据
|
||||
/// </summary>
|
||||
public class AppNetworkHourly : AppNetworkAggregatedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 小时时间戳(Unix时间戳,精确到小时)
|
||||
/// </summary>
|
||||
public long HourTimestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用网络天聚合数据
|
||||
/// </summary>
|
||||
public class AppNetworkDaily : AppNetworkAggregatedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 天时间戳(Unix时间戳,精确到天)
|
||||
/// </summary>
|
||||
public long DayTimestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用网络周聚合数据
|
||||
/// </summary>
|
||||
public class AppNetworkWeekly : AppNetworkAggregatedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 周时间戳(Unix时间戳,精确到周)
|
||||
/// </summary>
|
||||
public long WeekTimestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 应用网络月聚合数据
|
||||
/// </summary>
|
||||
public class AppNetworkMonthly : AppNetworkAggregatedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 月时间戳(Unix时间戳,精确到月)
|
||||
/// </summary>
|
||||
public long MonthTimestamp { get; set; }
|
||||
}
|
||||
@@ -17,17 +17,70 @@ public class AppSetting
|
||||
/// </summary>
|
||||
public int WindowY { get; set; } = 0;
|
||||
|
||||
/*
|
||||
*文本颜色
|
||||
背景颜色
|
||||
透明度
|
||||
速度单位
|
||||
布局方向(横向,纵向)
|
||||
展示单位(true/false)
|
||||
双击动作(1,2,3,)
|
||||
默认以管理员身份启动(true/false)
|
||||
*
|
||||
*/
|
||||
/// <summary>
|
||||
/// 点击穿透功能
|
||||
/// </summary>
|
||||
public bool IsClickThrough { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 位置锁定
|
||||
/// </summary>
|
||||
public bool IsPositionLocked { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 对齐到屏幕
|
||||
/// </summary>
|
||||
public bool SnapToScreen { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 显示详细信息
|
||||
/// </summary>
|
||||
public bool ShowDetailedInfo { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 窗口置顶
|
||||
/// </summary>
|
||||
public bool IsTopmost { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 文本颜色
|
||||
/// </summary>
|
||||
public string TextColor { get; set; } = "#FFFFFF";
|
||||
|
||||
/// <summary>
|
||||
/// 背景颜色
|
||||
/// </summary>
|
||||
public string BackgroundColor { get; set; } = "#000000";
|
||||
|
||||
/// <summary>
|
||||
/// 透明度 (0-100)
|
||||
/// </summary>
|
||||
public int Opacity { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 速度单位 (0: bps, 1: KB/s, 2: MB/s)
|
||||
/// </summary>
|
||||
public int SpeedUnit { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 布局方向 (0: 横向, 1: 纵向)
|
||||
/// </summary>
|
||||
public int LayoutDirection { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 展示单位
|
||||
/// </summary>
|
||||
public bool ShowUnit { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 双击动作 (0: None, 1: TrafficAnalysis, 2: Settings)
|
||||
/// </summary>
|
||||
public int DoubleClickAction { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 默认以管理员身份启动
|
||||
/// </summary>
|
||||
public bool RunAsAdmin { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否开机自启
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
namespace Data.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 全局网络聚合数据基类
|
||||
/// </summary>
|
||||
public abstract class GlobalNetworkAggregatedBase
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 网卡 GUID
|
||||
/// </summary>
|
||||
public string NetworkCardGuid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总上传字节数
|
||||
/// </summary>
|
||||
public long TotalUpload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总下载字节数
|
||||
/// </summary>
|
||||
public long TotalDownload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平均上传速度
|
||||
/// </summary>
|
||||
public long AvgUpload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平均下载速度
|
||||
/// </summary>
|
||||
public long AvgDownload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大上传速度
|
||||
/// </summary>
|
||||
public long MaxUpload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最大下载速度
|
||||
/// </summary>
|
||||
public long MaxDownload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录数量(用于计算平均值)
|
||||
/// </summary>
|
||||
public int RecordCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间戳
|
||||
/// </summary>
|
||||
public long CreatedTimestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全局网络小时聚合数据
|
||||
/// </summary>
|
||||
public class GlobalNetworkHourly : GlobalNetworkAggregatedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 小时时间戳(Unix时间戳,精确到小时)
|
||||
/// </summary>
|
||||
public long HourTimestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全局网络天聚合数据
|
||||
/// </summary>
|
||||
public class GlobalNetworkDaily : GlobalNetworkAggregatedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 天时间戳(Unix时间戳,精确到天)
|
||||
/// </summary>
|
||||
public long DayTimestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全局网络周聚合数据
|
||||
/// </summary>
|
||||
public class GlobalNetworkWeekly : GlobalNetworkAggregatedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 周时间戳(Unix时间戳,精确到周)
|
||||
/// </summary>
|
||||
public long WeekTimestamp { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全局网络月聚合数据
|
||||
/// </summary>
|
||||
public class GlobalNetworkMonthly : GlobalNetworkAggregatedBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 月时间戳(Unix时间戳,精确到月)
|
||||
/// </summary>
|
||||
public long MonthTimestamp { get; set; }
|
||||
}
|
||||
@@ -62,12 +62,25 @@ public class NetVizorDbContext : IDisposable
|
||||
DeleteTime INTEGER DEFAULT 0
|
||||
)");
|
||||
|
||||
// 创建AppSetting表 - 简化结构
|
||||
// 创建AppSetting表 - 完整结构
|
||||
await connection.ExecuteAsync(@"
|
||||
CREATE TABLE IF NOT EXISTS AppSetting (
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
WindowX INTEGER DEFAULT 0,
|
||||
WindowY INTEGER DEFAULT 0,
|
||||
IsClickThrough INTEGER DEFAULT 0,
|
||||
IsPositionLocked INTEGER DEFAULT 0,
|
||||
SnapToScreen INTEGER DEFAULT 0,
|
||||
ShowDetailedInfo INTEGER DEFAULT 0,
|
||||
IsTopmost INTEGER DEFAULT 0,
|
||||
TextColor TEXT DEFAULT '#FFFFFF',
|
||||
BackgroundColor TEXT DEFAULT '#000000',
|
||||
Opacity INTEGER DEFAULT 100,
|
||||
SpeedUnit INTEGER DEFAULT 1,
|
||||
LayoutDirection INTEGER DEFAULT 0,
|
||||
ShowUnit INTEGER DEFAULT 1,
|
||||
DoubleClickAction INTEGER DEFAULT 0,
|
||||
RunAsAdmin INTEGER DEFAULT 0,
|
||||
AutoStart INTEGER DEFAULT 0,
|
||||
UpdateTime INTEGER NOT NULL
|
||||
)");
|
||||
@@ -268,7 +281,8 @@ public class NetVizorDbContext : IDisposable
|
||||
var columns = await GetTableColumnsAsync("AppSetting");
|
||||
var needsMigration = columns.Contains("WindowWidth") || columns.Contains("WindowHeight") ||
|
||||
columns.Contains("Theme") || columns.Contains("Language") ||
|
||||
columns.Contains("MonitoringEnabled");
|
||||
columns.Contains("MonitoringEnabled") ||
|
||||
!columns.Contains("IsClickThrough") || !columns.Contains("TextColor");
|
||||
|
||||
if (needsMigration)
|
||||
{
|
||||
@@ -287,6 +301,19 @@ public class NetVizorDbContext : IDisposable
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
WindowX INTEGER DEFAULT 0,
|
||||
WindowY INTEGER DEFAULT 0,
|
||||
IsClickThrough INTEGER DEFAULT 0,
|
||||
IsPositionLocked INTEGER DEFAULT 0,
|
||||
SnapToScreen INTEGER DEFAULT 0,
|
||||
ShowDetailedInfo INTEGER DEFAULT 0,
|
||||
IsTopmost INTEGER DEFAULT 0,
|
||||
TextColor TEXT DEFAULT '#FFFFFF',
|
||||
BackgroundColor TEXT DEFAULT '#000000',
|
||||
Opacity INTEGER DEFAULT 100,
|
||||
SpeedUnit INTEGER DEFAULT 1,
|
||||
LayoutDirection INTEGER DEFAULT 0,
|
||||
ShowUnit INTEGER DEFAULT 1,
|
||||
DoubleClickAction INTEGER DEFAULT 0,
|
||||
RunAsAdmin INTEGER DEFAULT 0,
|
||||
AutoStart INTEGER DEFAULT 0,
|
||||
UpdateTime INTEGER NOT NULL
|
||||
)");
|
||||
|
||||
@@ -30,8 +30,16 @@ public class AppSettingRepository : IAppSettingRepository
|
||||
setting.UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
|
||||
const string sql = @"
|
||||
INSERT INTO AppSetting (WindowX, WindowY, AutoStart, UpdateTime)
|
||||
VALUES (@WindowX, @WindowY, @AutoStart, @UpdateTime)";
|
||||
INSERT INTO AppSetting (
|
||||
WindowX, WindowY, IsClickThrough, IsPositionLocked, SnapToScreen, ShowDetailedInfo,
|
||||
IsTopmost, TextColor, BackgroundColor, Opacity, SpeedUnit, LayoutDirection,
|
||||
ShowUnit, DoubleClickAction, RunAsAdmin, AutoStart, UpdateTime
|
||||
)
|
||||
VALUES (
|
||||
@WindowX, @WindowY, @IsClickThrough, @IsPositionLocked, @SnapToScreen, @ShowDetailedInfo,
|
||||
@IsTopmost, @TextColor, @BackgroundColor, @Opacity, @SpeedUnit, @LayoutDirection,
|
||||
@ShowUnit, @DoubleClickAction, @RunAsAdmin, @AutoStart, @UpdateTime
|
||||
)";
|
||||
|
||||
var result = await _context.Connection.ExecuteAsync(sql, setting);
|
||||
|
||||
@@ -49,7 +57,13 @@ public class AppSettingRepository : IAppSettingRepository
|
||||
|
||||
const string sql = @"
|
||||
UPDATE AppSetting
|
||||
SET WindowX = @WindowX, WindowY = @WindowY, AutoStart = @AutoStart, UpdateTime = @UpdateTime
|
||||
SET WindowX = @WindowX, WindowY = @WindowY, IsClickThrough = @IsClickThrough,
|
||||
IsPositionLocked = @IsPositionLocked, SnapToScreen = @SnapToScreen,
|
||||
ShowDetailedInfo = @ShowDetailedInfo, IsTopmost = @IsTopmost,
|
||||
TextColor = @TextColor, BackgroundColor = @BackgroundColor, Opacity = @Opacity,
|
||||
SpeedUnit = @SpeedUnit, LayoutDirection = @LayoutDirection, ShowUnit = @ShowUnit,
|
||||
DoubleClickAction = @DoubleClickAction, RunAsAdmin = @RunAsAdmin,
|
||||
AutoStart = @AutoStart, UpdateTime = @UpdateTime
|
||||
WHERE Id = @Id";
|
||||
|
||||
return await _context.Connection.ExecuteAsync(sql, setting);
|
||||
|
||||
@@ -59,11 +59,24 @@ public class DataService : IDataService, IDisposable
|
||||
{
|
||||
WindowX = 100,
|
||||
WindowY = 100,
|
||||
IsClickThrough = false,
|
||||
IsPositionLocked = false,
|
||||
SnapToScreen = false,
|
||||
ShowDetailedInfo = false,
|
||||
IsTopmost = false,
|
||||
TextColor = "#FFFFFF",
|
||||
BackgroundColor = "#000000",
|
||||
Opacity = 100,
|
||||
SpeedUnit = 1, // KB/s
|
||||
LayoutDirection = 0, // 横向
|
||||
ShowUnit = true,
|
||||
DoubleClickAction = 0, // None
|
||||
RunAsAdmin = false,
|
||||
AutoStart = false,
|
||||
UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||
};
|
||||
|
||||
setting.Id = await AppSettings.SaveSettingAsync(setting);
|
||||
await AppSettings.SaveSettingAsync(setting);
|
||||
}
|
||||
|
||||
return setting;
|
||||
|
||||
@@ -112,7 +112,11 @@ public class TrayIconManager : IDisposable
|
||||
{
|
||||
/* 菜单关闭 */
|
||||
};
|
||||
_contextMenu.LostFocus += (s, e) => _contextMenu.IsOpen = false;
|
||||
_contextMenu.LostFocus += (s, e) =>
|
||||
{
|
||||
if (_contextMenu != null)
|
||||
_contextMenu.IsOpen = false;
|
||||
};
|
||||
|
||||
// 展示主窗口(可勾选)
|
||||
var showMainWindowItem = new MenuItem
|
||||
@@ -124,7 +128,8 @@ public class TrayIconManager : IDisposable
|
||||
showMainWindowItem.Click += (s, e) =>
|
||||
{
|
||||
ToggleMainWindow();
|
||||
_contextMenu.IsOpen = false;
|
||||
if (_contextMenu != null)
|
||||
_contextMenu.IsOpen = false;
|
||||
};
|
||||
_contextMenu.Items.Add(showMainWindowItem);
|
||||
|
||||
@@ -140,7 +145,8 @@ public class TrayIconManager : IDisposable
|
||||
resetPositionItem.Click += (s, e) =>
|
||||
{
|
||||
ResetNetViewPosition();
|
||||
_contextMenu.IsOpen = false;
|
||||
if (_contextMenu != null)
|
||||
_contextMenu.IsOpen = false;
|
||||
};
|
||||
_contextMenu.Items.Add(resetPositionItem);
|
||||
|
||||
@@ -162,7 +168,8 @@ public class TrayIconManager : IDisposable
|
||||
detailedInfoItem.Click += (s, e) =>
|
||||
{
|
||||
ToggleDetailedInfo();
|
||||
_contextMenu.IsOpen = false;
|
||||
if (_contextMenu != null)
|
||||
_contextMenu.IsOpen = false;
|
||||
};
|
||||
_contextMenu.Items.Add(detailedInfoItem);
|
||||
|
||||
@@ -178,7 +185,8 @@ public class TrayIconManager : IDisposable
|
||||
trafficAnalysisItem.Click += (s, e) =>
|
||||
{
|
||||
OpenTrafficAnalysis();
|
||||
_contextMenu.IsOpen = false;
|
||||
if (_contextMenu != null)
|
||||
_contextMenu.IsOpen = false;
|
||||
};
|
||||
_contextMenu.Items.Add(trafficAnalysisItem);
|
||||
|
||||
@@ -191,7 +199,8 @@ public class TrayIconManager : IDisposable
|
||||
settingsItem.Click += (s, e) =>
|
||||
{
|
||||
OpenSettings();
|
||||
_contextMenu.IsOpen = false;
|
||||
if (_contextMenu != null)
|
||||
_contextMenu.IsOpen = false;
|
||||
};
|
||||
_contextMenu.Items.Add(settingsItem);
|
||||
|
||||
@@ -211,7 +220,10 @@ public class TrayIconManager : IDisposable
|
||||
exitItem.Click += (s, e) =>
|
||||
{
|
||||
ExitApplication();
|
||||
_contextMenu.IsOpen = false;
|
||||
if (_contextMenu != null)
|
||||
{
|
||||
_contextMenu.IsOpen = false;
|
||||
}
|
||||
};
|
||||
_contextMenu.Items.Add(exitItem);
|
||||
}
|
||||
@@ -299,8 +311,9 @@ public class TrayIconManager : IDisposable
|
||||
// 检查ESC键是否被按下
|
||||
if (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.Escape))
|
||||
{
|
||||
_contextMenu.IsOpen = false;
|
||||
_menuCloseTimer.Stop();
|
||||
if (_contextMenu != null)
|
||||
_contextMenu.IsOpen = false;
|
||||
_menuCloseTimer?.Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,8 +324,9 @@ public class TrayIconManager : IDisposable
|
||||
// 如果鼠标不在菜单区域内且有按键按下,则关闭菜单
|
||||
if (!IsMouseOverContextMenu())
|
||||
{
|
||||
_contextMenu.IsOpen = false;
|
||||
_menuCloseTimer.Stop();
|
||||
if (_contextMenu != null)
|
||||
_contextMenu.IsOpen = false;
|
||||
_menuCloseTimer?.Stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -324,7 +338,7 @@ public class TrayIconManager : IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!_contextMenu.IsOpen) return false;
|
||||
if (_contextMenu == null || !_contextMenu.IsOpen) return false;
|
||||
|
||||
// 获取屏幕上的鼠标位置
|
||||
GetCursorPos(out POINT screenPoint);
|
||||
@@ -356,12 +370,12 @@ public class TrayIconManager : IDisposable
|
||||
|
||||
private void UpdateContextMenuStates()
|
||||
{
|
||||
if (_mainWindow is Shell.Views.NetView netView)
|
||||
if (_mainWindow != null && _mainWindow is Shell.Views.NetView netView)
|
||||
{
|
||||
// 获取各个菜单项并更新状态
|
||||
foreach (var item in _contextMenu.Items.OfType<MenuItem>())
|
||||
{
|
||||
switch (item.Header.ToString())
|
||||
switch (item.Header?.ToString())
|
||||
{
|
||||
case "展示主窗口":
|
||||
item.IsChecked = netView.IsVisible;
|
||||
@@ -420,7 +434,7 @@ public class TrayIconManager : IDisposable
|
||||
|
||||
private void ResetNetViewPosition()
|
||||
{
|
||||
if (_mainWindow is Shell.Views.NetView netView)
|
||||
if (_mainWindow != null && _mainWindow is Shell.Views.NetView netView)
|
||||
{
|
||||
var workArea = SystemParameters.WorkArea;
|
||||
netView.Left = workArea.Right - netView.Width - 20;
|
||||
@@ -430,7 +444,7 @@ public class TrayIconManager : IDisposable
|
||||
|
||||
private void ToggleDetailedInfo()
|
||||
{
|
||||
if (_mainWindow is Shell.Views.NetView netView)
|
||||
if (_mainWindow != null && _mainWindow is Shell.Views.NetView netView)
|
||||
{
|
||||
var contextMenu = netView.ContextMenu;
|
||||
if (contextMenu?.Items != null)
|
||||
@@ -502,14 +516,39 @@ public class TrayIconManager : IDisposable
|
||||
{
|
||||
netView.ForceClose();
|
||||
}
|
||||
else if (_mainWindow != null)
|
||||
{
|
||||
// 如果不是NetView类型,直接关闭应用程序
|
||||
System.Windows.Application.Current?.Shutdown();
|
||||
}
|
||||
else
|
||||
{
|
||||
// _mainWindow为null时,直接关闭应用程序
|
||||
System.Windows.Application.Current?.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_notifyIcon?.Dispose();
|
||||
_contextMenu = null;
|
||||
_clickTimer?.Stop();
|
||||
_menuCloseTimer?.Stop();
|
||||
try
|
||||
{
|
||||
_clickTimer?.Stop();
|
||||
_menuCloseTimer?.Stop();
|
||||
|
||||
if (_contextMenu != null)
|
||||
{
|
||||
_contextMenu.IsOpen = false;
|
||||
_contextMenu = null;
|
||||
}
|
||||
|
||||
_notifyIcon?.Dispose();
|
||||
_mainWindow = null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 记录异常但不抛出,避免在Dispose中出现异常
|
||||
System.Diagnostics.Debug.WriteLine($"Error in TrayIconManager.Dispose: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,15 @@ using System.Windows.Interop;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using Shell.Utils;
|
||||
using Data;
|
||||
using Data.Models;
|
||||
|
||||
namespace Shell.Views;
|
||||
|
||||
public partial class NetView : Window
|
||||
{
|
||||
private TrayIconManager _trayIconManager;
|
||||
private bool _isClickThrough = false;
|
||||
private bool _isPositionLocked = false;
|
||||
private bool _snapToScreen = false;
|
||||
private bool _showDetailedInfo = false;
|
||||
private AppSetting _appSettings;
|
||||
|
||||
// Double-click detection
|
||||
private DispatcherTimer _doubleClickTimer;
|
||||
@@ -50,22 +49,22 @@ public partial class NetView : Window
|
||||
|
||||
// Initialize double-click timer
|
||||
InitializeDoubleClickTimer();
|
||||
|
||||
// Initialize settings - will be loaded asynchronously in OnLoaded
|
||||
_appSettings = new AppSetting();
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
private async void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// 重置位置
|
||||
ResetToDefaultPosition();
|
||||
// 从数据库加载设置
|
||||
await LoadSettingsFromDatabase();
|
||||
|
||||
// 应用设置到窗口
|
||||
ApplySettingsToWindow();
|
||||
}
|
||||
|
||||
private void NetView_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Initialize default position if needed
|
||||
if (this.Left == 0 && this.Top == 0)
|
||||
{
|
||||
ResetToDefaultPosition();
|
||||
}
|
||||
|
||||
// 设置窗口为工具窗口,隐藏在Alt+Tab中
|
||||
HideFromAltTab();
|
||||
|
||||
@@ -76,6 +75,74 @@ public partial class NetView : Window
|
||||
PopulateNetworkMenu();
|
||||
}
|
||||
|
||||
private async Task LoadSettingsFromDatabase()
|
||||
{
|
||||
try
|
||||
{
|
||||
_appSettings = await DatabaseManager.GetUserSettingsAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error loading settings from database: {ex.Message}");
|
||||
// 使用默认设置
|
||||
_appSettings = new AppSetting();
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySettingsToWindow()
|
||||
{
|
||||
// 应用窗口位置
|
||||
if (_appSettings.WindowX != 0 || _appSettings.WindowY != 0)
|
||||
{
|
||||
this.Left = _appSettings.WindowX;
|
||||
this.Top = _appSettings.WindowY;
|
||||
}
|
||||
else
|
||||
{
|
||||
ResetToDefaultPosition();
|
||||
}
|
||||
|
||||
// 应用其他窗口设置
|
||||
this.Topmost = _appSettings.IsTopmost;
|
||||
SetClickThrough(_appSettings.IsClickThrough);
|
||||
|
||||
// 更新菜单项的选中状态
|
||||
if (LockPositionMenuItem != null)
|
||||
LockPositionMenuItem.IsChecked = _appSettings.IsPositionLocked;
|
||||
if (ClickThroughMenuItem != null)
|
||||
ClickThroughMenuItem.IsChecked = _appSettings.IsClickThrough;
|
||||
if (TopmostMenuItem != null)
|
||||
TopmostMenuItem.IsChecked = _appSettings.IsTopmost;
|
||||
if (SnapToScreenMenuItem != null)
|
||||
SnapToScreenMenuItem.IsChecked = _appSettings.SnapToScreen;
|
||||
if (DetailedInfoMenuItem != null)
|
||||
DetailedInfoMenuItem.IsChecked = _appSettings.ShowDetailedInfo;
|
||||
}
|
||||
|
||||
private async Task SaveSettingsToDatabase()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 更新窗口位置
|
||||
_appSettings.WindowX = (int)this.Left;
|
||||
_appSettings.WindowY = (int)this.Top;
|
||||
|
||||
// 保存到数据库
|
||||
if (_appSettings.Id == 0)
|
||||
{
|
||||
await DatabaseManager.Instance.AppSettings.SaveSettingAsync(_appSettings);
|
||||
}
|
||||
else
|
||||
{
|
||||
await DatabaseManager.Instance.AppSettings.UpdateSettingAsync(_appSettings);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Error saving settings to database: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateNetworkMenu()
|
||||
{
|
||||
if (NetworkSelectionMenuItem != null)
|
||||
@@ -213,16 +280,15 @@ public partial class NetView : Window
|
||||
{
|
||||
try
|
||||
{
|
||||
var settings = Shell.Models.NetViewSettings.Instance;
|
||||
switch (settings.DoubleClickAction)
|
||||
switch (_appSettings.DoubleClickAction)
|
||||
{
|
||||
case Shell.Models.DoubleClickAction.TrafficAnalysis:
|
||||
case 1: // TrafficAnalysis
|
||||
TrafficAnalysisWindow.ShowWindow();
|
||||
break;
|
||||
case Shell.Models.DoubleClickAction.Settings:
|
||||
case 2: // Settings
|
||||
SettingsWindow.ShowWindow();
|
||||
break;
|
||||
case Shell.Models.DoubleClickAction.None:
|
||||
case 0: // None
|
||||
default:
|
||||
// 无动作
|
||||
break;
|
||||
@@ -296,20 +362,23 @@ public partial class NetView : Window
|
||||
this.Top = workArea.Top + 20;
|
||||
}
|
||||
|
||||
private void LockPosition_Click(object sender, RoutedEventArgs e)
|
||||
private async void LockPosition_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_isPositionLocked = !_isPositionLocked;
|
||||
LockPositionMenuItem.IsChecked = _isPositionLocked;
|
||||
_appSettings.IsPositionLocked = !_appSettings.IsPositionLocked;
|
||||
LockPositionMenuItem.IsChecked = _appSettings.IsPositionLocked;
|
||||
|
||||
// Don't change ResizeMode to maintain consistent window behavior
|
||||
// The dragging logic will check _isPositionLocked instead
|
||||
// 保存设置到数据库
|
||||
await SaveSettingsToDatabase();
|
||||
}
|
||||
|
||||
private void ToggleClickThrough_Click(object sender, RoutedEventArgs e)
|
||||
private async void ToggleClickThrough_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_isClickThrough = !_isClickThrough;
|
||||
ClickThroughMenuItem.IsChecked = _isClickThrough;
|
||||
SetClickThrough(_isClickThrough);
|
||||
_appSettings.IsClickThrough = !_appSettings.IsClickThrough;
|
||||
ClickThroughMenuItem.IsChecked = _appSettings.IsClickThrough;
|
||||
SetClickThrough(_appSettings.IsClickThrough);
|
||||
|
||||
// 保存设置到数据库
|
||||
await SaveSettingsToDatabase();
|
||||
}
|
||||
|
||||
private void SetClickThrough(bool enabled)
|
||||
@@ -329,21 +398,28 @@ public partial class NetView : Window
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleTopmost_Click(object sender, RoutedEventArgs e)
|
||||
private async void ToggleTopmost_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Topmost = !this.Topmost;
|
||||
TopmostMenuItem.IsChecked = this.Topmost;
|
||||
_appSettings.IsTopmost = !_appSettings.IsTopmost;
|
||||
this.Topmost = _appSettings.IsTopmost;
|
||||
TopmostMenuItem.IsChecked = _appSettings.IsTopmost;
|
||||
|
||||
// 保存设置到数据库
|
||||
await SaveSettingsToDatabase();
|
||||
}
|
||||
|
||||
private void ToggleSnapToScreen_Click(object sender, RoutedEventArgs e)
|
||||
private async void ToggleSnapToScreen_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_snapToScreen = !_snapToScreen;
|
||||
SnapToScreenMenuItem.IsChecked = _snapToScreen;
|
||||
_appSettings.SnapToScreen = !_appSettings.SnapToScreen;
|
||||
SnapToScreenMenuItem.IsChecked = _appSettings.SnapToScreen;
|
||||
|
||||
if (_snapToScreen)
|
||||
if (_appSettings.SnapToScreen)
|
||||
{
|
||||
SnapToScreen();
|
||||
}
|
||||
|
||||
// 保存设置到数据库
|
||||
await SaveSettingsToDatabase();
|
||||
}
|
||||
|
||||
private void SnapToScreen()
|
||||
@@ -356,10 +432,10 @@ public partial class NetView : Window
|
||||
this.Top = top;
|
||||
}
|
||||
|
||||
private void ToggleDetailedInfo_Click(object sender, RoutedEventArgs e)
|
||||
private async void ToggleDetailedInfo_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_showDetailedInfo = !_showDetailedInfo;
|
||||
DetailedInfoMenuItem.IsChecked = _showDetailedInfo;
|
||||
_appSettings.ShowDetailedInfo = !_appSettings.ShowDetailedInfo;
|
||||
DetailedInfoMenuItem.IsChecked = _appSettings.ShowDetailedInfo;
|
||||
|
||||
// The window will automatically resize based on content
|
||||
// No need to manually set height anymore due to SizeToContent="WidthAndHeight"
|
||||
@@ -367,6 +443,9 @@ public partial class NetView : Window
|
||||
// You can trigger a re-layout if needed
|
||||
this.InvalidateMeasure();
|
||||
this.UpdateLayout();
|
||||
|
||||
// 保存设置到数据库
|
||||
await SaveSettingsToDatabase();
|
||||
}
|
||||
|
||||
private void HideToTray_Click(object sender, RoutedEventArgs e)
|
||||
@@ -431,7 +510,7 @@ public partial class NetView : Window
|
||||
}
|
||||
|
||||
// Only allow dragging if position is not locked and click-through is disabled
|
||||
if (!_isPositionLocked && !_isClickThrough)
|
||||
if (!_appSettings.IsPositionLocked && !_appSettings.IsClickThrough)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -450,16 +529,19 @@ public partial class NetView : Window
|
||||
base.OnLocationChanged(e);
|
||||
|
||||
// Only check snap to screen if that option is enabled
|
||||
if (_snapToScreen && !_isPositionLocked)
|
||||
if (_appSettings.SnapToScreen && !_appSettings.IsPositionLocked)
|
||||
{
|
||||
SnapToScreen();
|
||||
}
|
||||
|
||||
// Perform boundary check after drag is complete (with delay to avoid flicker)
|
||||
if (!_isPositionLocked)
|
||||
if (!_appSettings.IsPositionLocked)
|
||||
{
|
||||
CheckBoundariesDelayed();
|
||||
}
|
||||
|
||||
// 自动保存位置变化
|
||||
_ = Task.Run(async () => await SaveSettingsToDatabase());
|
||||
}
|
||||
|
||||
private System.Windows.Threading.DispatcherTimer? _boundaryCheckTimer;
|
||||
|
||||
Reference in new issue
Block a user