Refactor MonitorStateManager and MainViewModel to use HardwareId for stable identification; update logging for clarity and consistency.

This commit is contained in:
Yu Leng (from Dev Box)
2025-10-17 18:03:13 +08:00
parent c2d82a72ca
commit bda629c70a
2 changed files with 44 additions and 28 deletions

View File

@@ -71,6 +71,8 @@ namespace PowerDisplay.Helpers
/// <summary>
/// Serializable state for JSON persistence
/// Dictionary key should be HardwareId (e.g., "GSM5C6D") for stable identification
/// Legacy files may have used InternalName (e.g., "DISPLAY1_0_3") which will still load but won't match after reconnection
/// </summary>
private sealed class MonitorStateFile
{
@@ -116,13 +118,20 @@ namespace PowerDisplay.Helpers
/// <summary>
/// Update monitor parameter in memory (lock-free, non-blocking)
/// Uses HardwareId as the stable key
/// </summary>
public void UpdateMonitorParameter(string monitorId, string property, int value)
public void UpdateMonitorParameter(string hardwareId, string property, int value)
{
try
{
// Get or create parameter entry
var parameters = _parameters.GetOrAdd(monitorId, _ => new MonitorParameters());
if (string.IsNullOrEmpty(hardwareId))
{
Logger.LogWarning($"Cannot update monitor parameter: HardwareId is empty");
return;
}
// Get or create parameter entry using HardwareId
var parameters = _parameters.GetOrAdd(hardwareId, _ => new MonitorParameters());
// Update the specific property (volatile write)
switch (property)
@@ -147,7 +156,7 @@ namespace PowerDisplay.Helpers
// Mark as dirty (will be saved in next timer cycle)
_isDirty = true;
Logger.LogTrace($"[State] Updated {property}={value} for monitor '{monitorId}'");
Logger.LogTrace($"[State] Updated {property}={value} for monitor HardwareId='{hardwareId}'");
}
catch (Exception ex)
{
@@ -156,11 +165,16 @@ namespace PowerDisplay.Helpers
}
/// <summary>
/// Get saved parameters for a monitor
/// Get saved parameters for a monitor using HardwareId
/// </summary>
public (int Brightness, int ColorTemperature, int Contrast, int Volume)? GetMonitorParameters(string monitorId)
public (int Brightness, int ColorTemperature, int Contrast, int Volume)? GetMonitorParameters(string hardwareId)
{
if (_parameters.TryGetValue(monitorId, out var parameters))
if (string.IsNullOrEmpty(hardwareId))
{
return null;
}
if (_parameters.TryGetValue(hardwareId, out var parameters))
{
return (parameters.Brightness, parameters.ColorTemperature, parameters.Contrast, parameters.Volume);
}
@@ -168,11 +182,11 @@ namespace PowerDisplay.Helpers
}
/// <summary>
/// Check if state exists for a monitor
/// Check if state exists for a monitor (by HardwareId)
/// </summary>
public bool HasMonitorState(string monitorId)
public bool HasMonitorState(string hardwareId)
{
return _parameters.ContainsKey(monitorId);
return !string.IsNullOrEmpty(hardwareId) && _parameters.ContainsKey(hardwareId);
}
/// <summary>
@@ -195,10 +209,10 @@ namespace PowerDisplay.Helpers
{
foreach (var kvp in state.Monitors)
{
var monitorId = kvp.Key;
var monitorKey = kvp.Key; // Should be HardwareId (e.g., "GSM5C6D")
var entry = kvp.Value;
var parameters = _parameters.GetOrAdd(monitorId, _ => new MonitorParameters());
var parameters = _parameters.GetOrAdd(monitorKey, _ => new MonitorParameters());
parameters.Brightness = entry.Brightness;
parameters.ColorTemperature = entry.ColorTemperature;
parameters.Contrast = entry.Contrast;
@@ -206,6 +220,7 @@ namespace PowerDisplay.Helpers
}
Logger.LogInfo($"[State] Loaded state for {state.Monitors.Count} monitors from {_stateFilePath}");
Logger.LogInfo($"[State] Monitor keys in state file: {string.Join(", ", state.Monitors.Keys)}");
}
}
catch (Exception ex)

View File

@@ -487,14 +487,14 @@ public class MainViewModel : INotifyPropertyChanged, IDisposable
foreach (var monitorVm in Monitors)
{
var internalName = GetInternalName(monitorVm);
Logger.LogInfo($"[Startup] Processing monitor: '{monitorVm.Name}', InternalName: '{internalName}'");
var hardwareId = monitorVm.HardwareId;
Logger.LogInfo($"[Startup] Processing monitor: '{monitorVm.Name}', HardwareId: '{hardwareId}'");
// Find and apply corresponding saved settings from state file
var savedState = _stateManager.GetMonitorParameters(internalName);
// Find and apply corresponding saved settings from state file using stable HardwareId
var savedState = _stateManager.GetMonitorParameters(hardwareId);
if (savedState.HasValue)
{
Logger.LogInfo($"[Startup] Restoring state for '{internalName}': Brightness={savedState.Value.Brightness}, ColorTemp={savedState.Value.ColorTemperature}");
Logger.LogInfo($"[Startup] Restoring state for HardwareId '{hardwareId}': Brightness={savedState.Value.Brightness}, ColorTemp={savedState.Value.ColorTemperature}");
// 验证并应用保存的值(跳过无效值)
if (savedState.Value.Brightness >= monitorVm.MinBrightness && savedState.Value.Brightness <= monitorVm.MaxBrightness)
@@ -503,7 +503,7 @@ public class MainViewModel : INotifyPropertyChanged, IDisposable
}
else
{
Logger.LogWarning($"[Startup] Invalid brightness value {savedState.Value.Brightness} for '{internalName}', skipping");
Logger.LogWarning($"[Startup] Invalid brightness value {savedState.Value.Brightness} for HardwareId '{hardwareId}', skipping");
}
// 色温值必须有效且在范围内
@@ -515,7 +515,7 @@ public class MainViewModel : INotifyPropertyChanged, IDisposable
}
else
{
Logger.LogWarning($"[Startup] Invalid color temperature value {savedState.Value.ColorTemperature} for '{internalName}', skipping");
Logger.LogWarning($"[Startup] Invalid color temperature value {savedState.Value.ColorTemperature} for HardwareId '{hardwareId}', skipping");
}
// 对比度值验证 - 只在硬件支持的情况下才应用
@@ -527,7 +527,7 @@ public class MainViewModel : INotifyPropertyChanged, IDisposable
}
else if (!monitorVm.ShowContrast)
{
Logger.LogInfo($"[Startup] Contrast not supported on '{internalName}', skipping");
Logger.LogInfo($"[Startup] Contrast not supported on HardwareId '{hardwareId}', skipping");
}
// 音量值验证 - 只在硬件支持的情况下才应用
@@ -539,15 +539,16 @@ public class MainViewModel : INotifyPropertyChanged, IDisposable
}
else if (!monitorVm.ShowVolume)
{
Logger.LogInfo($"[Startup] Volume not supported on '{internalName}', skipping");
Logger.LogInfo($"[Startup] Volume not supported on HardwareId '{hardwareId}', skipping");
}
}
else
{
Logger.LogInfo($"[Startup] No saved state for '{internalName}' - keeping current hardware values");
Logger.LogInfo($"[Startup] No saved state for HardwareId '{hardwareId}' - keeping current hardware values");
}
// Apply feature visibility settings
// Apply feature visibility settings (still need InternalName for Settings UI matching)
var internalName = GetInternalName(monitorVm);
ApplyFeatureVisibility(monitorVm, settings, internalName);
}
@@ -634,7 +635,7 @@ public class MainViewModel : INotifyPropertyChanged, IDisposable
{
try
{
// Find the monitor VM to get the converted internal name
// Find the monitor VM to get the stable HardwareId
var monitorVm = GetMonitorViewModel(monitorId);
if (monitorVm == null)
{
@@ -642,13 +643,13 @@ public class MainViewModel : INotifyPropertyChanged, IDisposable
return;
}
// Use converted internal name for consistency with Settings UI
var internalName = GetInternalName(monitorVm);
// Use stable HardwareId as the key for state persistence
var hardwareId = monitorVm.HardwareId;
// Update parameter in state file (lock-free, non-blocking)
_stateManager.UpdateMonitorParameter(internalName, property, value);
_stateManager.UpdateMonitorParameter(hardwareId, property, value);
Logger.LogTrace($"[State] Queued setting change for '{internalName}': {property}={value}");
Logger.LogTrace($"[State] Queued setting change for HardwareId '{hardwareId}': {property}={value}");
}
catch (Exception ex)
{