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>
|
/// </summary>
|
||||||
public int WindowY { get; set; } = 0;
|
public int WindowY { get; set; } = 0;
|
||||||
|
|
||||||
/*
|
/// <summary>
|
||||||
*文本颜色
|
/// 点击穿透功能
|
||||||
背景颜色
|
/// </summary>
|
||||||
透明度
|
public bool IsClickThrough { get; set; } = false;
|
||||||
速度单位
|
|
||||||
布局方向(横向,纵向)
|
/// <summary>
|
||||||
展示单位(true/false)
|
/// 位置锁定
|
||||||
双击动作(1,2,3,)
|
/// </summary>
|
||||||
默认以管理员身份启动(true/false)
|
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>
|
/// <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
|
DeleteTime INTEGER DEFAULT 0
|
||||||
)");
|
)");
|
||||||
|
|
||||||
// 创建AppSetting表 - 简化结构
|
// 创建AppSetting表 - 完整结构
|
||||||
await connection.ExecuteAsync(@"
|
await connection.ExecuteAsync(@"
|
||||||
CREATE TABLE IF NOT EXISTS AppSetting (
|
CREATE TABLE IF NOT EXISTS AppSetting (
|
||||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
WindowX INTEGER DEFAULT 0,
|
WindowX INTEGER DEFAULT 0,
|
||||||
WindowY 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,
|
AutoStart INTEGER DEFAULT 0,
|
||||||
UpdateTime INTEGER NOT NULL
|
UpdateTime INTEGER NOT NULL
|
||||||
)");
|
)");
|
||||||
@@ -268,7 +281,8 @@ public class NetVizorDbContext : IDisposable
|
|||||||
var columns = await GetTableColumnsAsync("AppSetting");
|
var columns = await GetTableColumnsAsync("AppSetting");
|
||||||
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");
|
||||||
|
|
||||||
if (needsMigration)
|
if (needsMigration)
|
||||||
{
|
{
|
||||||
@@ -287,6 +301,19 @@ public class NetVizorDbContext : IDisposable
|
|||||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
WindowX INTEGER DEFAULT 0,
|
WindowX INTEGER DEFAULT 0,
|
||||||
WindowY 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,
|
AutoStart INTEGER DEFAULT 0,
|
||||||
UpdateTime INTEGER NOT NULL
|
UpdateTime INTEGER NOT NULL
|
||||||
)");
|
)");
|
||||||
|
|||||||
@@ -30,8 +30,16 @@ public class AppSettingRepository : IAppSettingRepository
|
|||||||
setting.UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
setting.UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||||
|
|
||||||
const string sql = @"
|
const string sql = @"
|
||||||
INSERT INTO AppSetting (WindowX, WindowY, AutoStart, UpdateTime)
|
INSERT INTO AppSetting (
|
||||||
VALUES (@WindowX, @WindowY, @AutoStart, @UpdateTime)";
|
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);
|
var result = await _context.Connection.ExecuteAsync(sql, setting);
|
||||||
|
|
||||||
@@ -49,7 +57,13 @@ public class AppSettingRepository : IAppSettingRepository
|
|||||||
|
|
||||||
const string sql = @"
|
const string sql = @"
|
||||||
UPDATE AppSetting
|
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";
|
WHERE Id = @Id";
|
||||||
|
|
||||||
return await _context.Connection.ExecuteAsync(sql, setting);
|
return await _context.Connection.ExecuteAsync(sql, setting);
|
||||||
|
|||||||
@@ -59,11 +59,24 @@ public class DataService : IDataService, IDisposable
|
|||||||
{
|
{
|
||||||
WindowX = 100,
|
WindowX = 100,
|
||||||
WindowY = 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,
|
AutoStart = false,
|
||||||
UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
UpdateTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||||
};
|
};
|
||||||
|
|
||||||
setting.Id = await AppSettings.SaveSettingAsync(setting);
|
await AppSettings.SaveSettingAsync(setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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
|
var showMainWindowItem = new MenuItem
|
||||||
@@ -124,7 +128,8 @@ public class TrayIconManager : IDisposable
|
|||||||
showMainWindowItem.Click += (s, e) =>
|
showMainWindowItem.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
ToggleMainWindow();
|
ToggleMainWindow();
|
||||||
_contextMenu.IsOpen = false;
|
if (_contextMenu != null)
|
||||||
|
_contextMenu.IsOpen = false;
|
||||||
};
|
};
|
||||||
_contextMenu.Items.Add(showMainWindowItem);
|
_contextMenu.Items.Add(showMainWindowItem);
|
||||||
|
|
||||||
@@ -140,7 +145,8 @@ public class TrayIconManager : IDisposable
|
|||||||
resetPositionItem.Click += (s, e) =>
|
resetPositionItem.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
ResetNetViewPosition();
|
ResetNetViewPosition();
|
||||||
_contextMenu.IsOpen = false;
|
if (_contextMenu != null)
|
||||||
|
_contextMenu.IsOpen = false;
|
||||||
};
|
};
|
||||||
_contextMenu.Items.Add(resetPositionItem);
|
_contextMenu.Items.Add(resetPositionItem);
|
||||||
|
|
||||||
@@ -162,7 +168,8 @@ public class TrayIconManager : IDisposable
|
|||||||
detailedInfoItem.Click += (s, e) =>
|
detailedInfoItem.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
ToggleDetailedInfo();
|
ToggleDetailedInfo();
|
||||||
_contextMenu.IsOpen = false;
|
if (_contextMenu != null)
|
||||||
|
_contextMenu.IsOpen = false;
|
||||||
};
|
};
|
||||||
_contextMenu.Items.Add(detailedInfoItem);
|
_contextMenu.Items.Add(detailedInfoItem);
|
||||||
|
|
||||||
@@ -178,7 +185,8 @@ public class TrayIconManager : IDisposable
|
|||||||
trafficAnalysisItem.Click += (s, e) =>
|
trafficAnalysisItem.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
OpenTrafficAnalysis();
|
OpenTrafficAnalysis();
|
||||||
_contextMenu.IsOpen = false;
|
if (_contextMenu != null)
|
||||||
|
_contextMenu.IsOpen = false;
|
||||||
};
|
};
|
||||||
_contextMenu.Items.Add(trafficAnalysisItem);
|
_contextMenu.Items.Add(trafficAnalysisItem);
|
||||||
|
|
||||||
@@ -191,7 +199,8 @@ public class TrayIconManager : IDisposable
|
|||||||
settingsItem.Click += (s, e) =>
|
settingsItem.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
OpenSettings();
|
OpenSettings();
|
||||||
_contextMenu.IsOpen = false;
|
if (_contextMenu != null)
|
||||||
|
_contextMenu.IsOpen = false;
|
||||||
};
|
};
|
||||||
_contextMenu.Items.Add(settingsItem);
|
_contextMenu.Items.Add(settingsItem);
|
||||||
|
|
||||||
@@ -211,7 +220,10 @@ public class TrayIconManager : IDisposable
|
|||||||
exitItem.Click += (s, e) =>
|
exitItem.Click += (s, e) =>
|
||||||
{
|
{
|
||||||
ExitApplication();
|
ExitApplication();
|
||||||
_contextMenu.IsOpen = false;
|
if (_contextMenu != null)
|
||||||
|
{
|
||||||
|
_contextMenu.IsOpen = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
_contextMenu.Items.Add(exitItem);
|
_contextMenu.Items.Add(exitItem);
|
||||||
}
|
}
|
||||||
@@ -299,8 +311,9 @@ public class TrayIconManager : IDisposable
|
|||||||
// 检查ESC键是否被按下
|
// 检查ESC键是否被按下
|
||||||
if (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.Escape))
|
if (System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.Escape))
|
||||||
{
|
{
|
||||||
_contextMenu.IsOpen = false;
|
if (_contextMenu != null)
|
||||||
_menuCloseTimer.Stop();
|
_contextMenu.IsOpen = false;
|
||||||
|
_menuCloseTimer?.Stop();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,8 +324,9 @@ public class TrayIconManager : IDisposable
|
|||||||
// 如果鼠标不在菜单区域内且有按键按下,则关闭菜单
|
// 如果鼠标不在菜单区域内且有按键按下,则关闭菜单
|
||||||
if (!IsMouseOverContextMenu())
|
if (!IsMouseOverContextMenu())
|
||||||
{
|
{
|
||||||
_contextMenu.IsOpen = false;
|
if (_contextMenu != null)
|
||||||
_menuCloseTimer.Stop();
|
_contextMenu.IsOpen = false;
|
||||||
|
_menuCloseTimer?.Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -324,7 +338,7 @@ public class TrayIconManager : IDisposable
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!_contextMenu.IsOpen) return false;
|
if (_contextMenu == null || !_contextMenu.IsOpen) return false;
|
||||||
|
|
||||||
// 获取屏幕上的鼠标位置
|
// 获取屏幕上的鼠标位置
|
||||||
GetCursorPos(out POINT screenPoint);
|
GetCursorPos(out POINT screenPoint);
|
||||||
@@ -356,12 +370,12 @@ public class TrayIconManager : IDisposable
|
|||||||
|
|
||||||
private void UpdateContextMenuStates()
|
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>())
|
foreach (var item in _contextMenu.Items.OfType<MenuItem>())
|
||||||
{
|
{
|
||||||
switch (item.Header.ToString())
|
switch (item.Header?.ToString())
|
||||||
{
|
{
|
||||||
case "展示主窗口":
|
case "展示主窗口":
|
||||||
item.IsChecked = netView.IsVisible;
|
item.IsChecked = netView.IsVisible;
|
||||||
@@ -420,7 +434,7 @@ public class TrayIconManager : IDisposable
|
|||||||
|
|
||||||
private void ResetNetViewPosition()
|
private void ResetNetViewPosition()
|
||||||
{
|
{
|
||||||
if (_mainWindow is Shell.Views.NetView netView)
|
if (_mainWindow != null && _mainWindow is Shell.Views.NetView netView)
|
||||||
{
|
{
|
||||||
var workArea = SystemParameters.WorkArea;
|
var workArea = SystemParameters.WorkArea;
|
||||||
netView.Left = workArea.Right - netView.Width - 20;
|
netView.Left = workArea.Right - netView.Width - 20;
|
||||||
@@ -430,7 +444,7 @@ public class TrayIconManager : IDisposable
|
|||||||
|
|
||||||
private void ToggleDetailedInfo()
|
private void ToggleDetailedInfo()
|
||||||
{
|
{
|
||||||
if (_mainWindow is Shell.Views.NetView netView)
|
if (_mainWindow != null && _mainWindow is Shell.Views.NetView netView)
|
||||||
{
|
{
|
||||||
var contextMenu = netView.ContextMenu;
|
var contextMenu = netView.ContextMenu;
|
||||||
if (contextMenu?.Items != null)
|
if (contextMenu?.Items != null)
|
||||||
@@ -502,14 +516,39 @@ public class TrayIconManager : IDisposable
|
|||||||
{
|
{
|
||||||
netView.ForceClose();
|
netView.ForceClose();
|
||||||
}
|
}
|
||||||
|
else if (_mainWindow != null)
|
||||||
|
{
|
||||||
|
// 如果不是NetView类型,直接关闭应用程序
|
||||||
|
System.Windows.Application.Current?.Shutdown();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// _mainWindow为null时,直接关闭应用程序
|
||||||
|
System.Windows.Application.Current?.Shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_notifyIcon?.Dispose();
|
try
|
||||||
_contextMenu = null;
|
{
|
||||||
_clickTimer?.Stop();
|
_clickTimer?.Stop();
|
||||||
_menuCloseTimer?.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.Media;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Shell.Utils;
|
using Shell.Utils;
|
||||||
|
using Data;
|
||||||
|
using Data.Models;
|
||||||
|
|
||||||
namespace Shell.Views;
|
namespace Shell.Views;
|
||||||
|
|
||||||
public partial class NetView : Window
|
public partial class NetView : Window
|
||||||
{
|
{
|
||||||
private TrayIconManager _trayIconManager;
|
private TrayIconManager _trayIconManager;
|
||||||
private bool _isClickThrough = false;
|
private AppSetting _appSettings;
|
||||||
private bool _isPositionLocked = false;
|
|
||||||
private bool _snapToScreen = false;
|
|
||||||
private bool _showDetailedInfo = false;
|
|
||||||
|
|
||||||
// Double-click detection
|
// Double-click detection
|
||||||
private DispatcherTimer _doubleClickTimer;
|
private DispatcherTimer _doubleClickTimer;
|
||||||
@@ -50,22 +49,22 @@ public partial class NetView : Window
|
|||||||
|
|
||||||
// Initialize double-click timer
|
// Initialize double-click timer
|
||||||
InitializeDoubleClickTimer();
|
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)
|
private void NetView_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
// Initialize default position if needed
|
|
||||||
if (this.Left == 0 && this.Top == 0)
|
|
||||||
{
|
|
||||||
ResetToDefaultPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置窗口为工具窗口,隐藏在Alt+Tab中
|
// 设置窗口为工具窗口,隐藏在Alt+Tab中
|
||||||
HideFromAltTab();
|
HideFromAltTab();
|
||||||
|
|
||||||
@@ -76,6 +75,74 @@ public partial class NetView : Window
|
|||||||
PopulateNetworkMenu();
|
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()
|
private void PopulateNetworkMenu()
|
||||||
{
|
{
|
||||||
if (NetworkSelectionMenuItem != null)
|
if (NetworkSelectionMenuItem != null)
|
||||||
@@ -213,16 +280,15 @@ public partial class NetView : Window
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var settings = Shell.Models.NetViewSettings.Instance;
|
switch (_appSettings.DoubleClickAction)
|
||||||
switch (settings.DoubleClickAction)
|
|
||||||
{
|
{
|
||||||
case Shell.Models.DoubleClickAction.TrafficAnalysis:
|
case 1: // TrafficAnalysis
|
||||||
TrafficAnalysisWindow.ShowWindow();
|
TrafficAnalysisWindow.ShowWindow();
|
||||||
break;
|
break;
|
||||||
case Shell.Models.DoubleClickAction.Settings:
|
case 2: // Settings
|
||||||
SettingsWindow.ShowWindow();
|
SettingsWindow.ShowWindow();
|
||||||
break;
|
break;
|
||||||
case Shell.Models.DoubleClickAction.None:
|
case 0: // None
|
||||||
default:
|
default:
|
||||||
// 无动作
|
// 无动作
|
||||||
break;
|
break;
|
||||||
@@ -296,20 +362,23 @@ public partial class NetView : Window
|
|||||||
this.Top = workArea.Top + 20;
|
this.Top = workArea.Top + 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LockPosition_Click(object sender, RoutedEventArgs e)
|
private async void LockPosition_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_isPositionLocked = !_isPositionLocked;
|
_appSettings.IsPositionLocked = !_appSettings.IsPositionLocked;
|
||||||
LockPositionMenuItem.IsChecked = _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;
|
_appSettings.IsClickThrough = !_appSettings.IsClickThrough;
|
||||||
ClickThroughMenuItem.IsChecked = _isClickThrough;
|
ClickThroughMenuItem.IsChecked = _appSettings.IsClickThrough;
|
||||||
SetClickThrough(_isClickThrough);
|
SetClickThrough(_appSettings.IsClickThrough);
|
||||||
|
|
||||||
|
// 保存设置到数据库
|
||||||
|
await SaveSettingsToDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetClickThrough(bool enabled)
|
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;
|
_appSettings.IsTopmost = !_appSettings.IsTopmost;
|
||||||
TopmostMenuItem.IsChecked = this.Topmost;
|
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;
|
_appSettings.SnapToScreen = !_appSettings.SnapToScreen;
|
||||||
SnapToScreenMenuItem.IsChecked = _snapToScreen;
|
SnapToScreenMenuItem.IsChecked = _appSettings.SnapToScreen;
|
||||||
|
|
||||||
if (_snapToScreen)
|
if (_appSettings.SnapToScreen)
|
||||||
{
|
{
|
||||||
SnapToScreen();
|
SnapToScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 保存设置到数据库
|
||||||
|
await SaveSettingsToDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SnapToScreen()
|
private void SnapToScreen()
|
||||||
@@ -356,10 +432,10 @@ public partial class NetView : Window
|
|||||||
this.Top = top;
|
this.Top = top;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleDetailedInfo_Click(object sender, RoutedEventArgs e)
|
private async void ToggleDetailedInfo_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_showDetailedInfo = !_showDetailedInfo;
|
_appSettings.ShowDetailedInfo = !_appSettings.ShowDetailedInfo;
|
||||||
DetailedInfoMenuItem.IsChecked = _showDetailedInfo;
|
DetailedInfoMenuItem.IsChecked = _appSettings.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"
|
||||||
@@ -367,6 +443,9 @@ public partial class NetView : Window
|
|||||||
// You can trigger a re-layout if needed
|
// You can trigger a re-layout if needed
|
||||||
this.InvalidateMeasure();
|
this.InvalidateMeasure();
|
||||||
this.UpdateLayout();
|
this.UpdateLayout();
|
||||||
|
|
||||||
|
// 保存设置到数据库
|
||||||
|
await SaveSettingsToDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HideToTray_Click(object sender, RoutedEventArgs e)
|
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
|
// Only allow dragging if position is not locked and click-through is disabled
|
||||||
if (!_isPositionLocked && !_isClickThrough)
|
if (!_appSettings.IsPositionLocked && !_appSettings.IsClickThrough)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -450,16 +529,19 @@ public partial class NetView : Window
|
|||||||
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 (_appSettings.SnapToScreen && !_appSettings.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 (!_appSettings.IsPositionLocked)
|
||||||
{
|
{
|
||||||
CheckBoundariesDelayed();
|
CheckBoundariesDelayed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自动保存位置变化
|
||||||
|
_ = Task.Run(async () => await SaveSettingsToDatabase());
|
||||||
}
|
}
|
||||||
|
|
||||||
private System.Windows.Threading.DispatcherTimer? _boundaryCheckTimer;
|
private System.Windows.Threading.DispatcherTimer? _boundaryCheckTimer;
|
||||||
|
|||||||
Reference in new issue
Block a user