controlmymonitormanagement/DellMonitorControl/MainWindow.xaml.cs
Dave Friedel 0352c6b755 Add brightness/contrast sliders, input source switching, and 9-language localization
- Add VCP commands for brightness (10), contrast (12), input source (60)
- Fix UTF-16 encoding for monitor data parsing
- Add system tray app with monitor controls
- Add localization for en, es, fr, de, zh, ja, pt, it, hi
- Update to .NET 9.0
- Add LICENSE and README

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 22:11:35 -05:00

172 lines
6.9 KiB
C#

using CMM.Library.Method;
using CMM.Library.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace DellMonitorControl;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
PositionWindowNearTray();
Loaded += async (s, e) => await LoadMonitors();
}
private void PositionWindowNearTray()
{
var workArea = SystemParameters.WorkArea;
Left = workArea.Right - Width - 10;
Top = workArea.Bottom - Height - 10;
}
private static readonly string LogFile = System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "MonitorControl.log");
private static void Log(string msg)
{
try { System.IO.File.AppendAllText(LogFile, $"{DateTime.Now:HH:mm:ss.fff} {msg}\n"); }
catch { }
}
private async Task LoadMonitors()
{
var newChildren = new List<UIElement>();
Log("LoadMonitors started");
try
{
Log("Calling ScanMonitor...");
await CMMCommand.ScanMonitor();
Log("ScanMonitor complete");
Log("Calling ReadMonitorsData...");
var monitors = (await CMMCommand.ReadMonitorsData()).ToList();
Log($"ReadMonitorsData complete, found {monitors.Count} monitors");
if (!monitors.Any())
{
Log("No monitors found");
newChildren.Add(new TextBlock { Text = "No DDC/CI monitors detected", Foreground = Brushes.White, FontSize = 14 });
}
else
{
foreach (var m in monitors)
{
Log($"Processing monitor: {m.MonitorName} ({m.SerialNumber})");
var brightness = await CMMCommand.GetBrightness(m.SerialNumber) ?? 50;
Log($" Brightness: {brightness}");
var contrast = await CMMCommand.GetContrast(m.SerialNumber) ?? 50;
Log($" Contrast: {contrast}");
var inputSource = await CMMCommand.GetInputSource(m.SerialNumber);
Log($" InputSource: {inputSource}");
var inputOptions = await CMMCommand.GetInputSourceOptions(m.SerialNumber);
Log($" InputOptions count: {inputOptions.Count}");
var powerStatus = await CMMCommand.GetMonPowerStatus(m.SerialNumber) ?? "Unknown";
Log($" PowerStatus: {powerStatus}");
newChildren.Add(new TextBlock
{
Text = m.MonitorName,
Foreground = Brushes.White,
FontSize = 14,
FontWeight = FontWeights.Bold,
Margin = new Thickness(0, 10, 0, 5)
});
newChildren.Add(CreateSliderRow("Brightness", brightness, m.SerialNumber, CMMCommand.SetBrightness));
newChildren.Add(CreateSliderRow("Contrast", contrast, m.SerialNumber, CMMCommand.SetContrast));
if (inputOptions.Count > 0)
newChildren.Add(CreateInputRow(inputSource, inputOptions, m.SerialNumber));
newChildren.Add(CreatePowerRow(powerStatus, m.SerialNumber));
}
}
Log($"Built {newChildren.Count} UI elements");
}
catch (Exception ex)
{
Log($"ERROR: {ex.GetType().Name}: {ex.Message}\n{ex.StackTrace}");
newChildren.Clear();
newChildren.Add(new TextBlock { Text = $"Error: {ex.Message}", Foreground = Brushes.Red, FontSize = 12, TextWrapping = TextWrapping.Wrap });
}
Log("Updating UI...");
sp.Children.Clear();
foreach (var child in newChildren)
sp.Children.Add(child);
Log($"UI updated with {sp.Children.Count} children");
}
private StackPanel CreateSliderRow(string label, int value, string serialNumber, Func<string, int, Task> setCommand)
{
var row = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) };
row.Children.Add(new TextBlock { Text = label, Foreground = Brushes.LightGray, Width = 70, FontSize = 12, VerticalAlignment = VerticalAlignment.Center });
var slider = new Slider { Minimum = 0, Maximum = 100, Value = value, Width = 140, Tag = serialNumber };
var valueText = new TextBlock { Text = value.ToString(), Foreground = Brushes.White, Width = 30, FontSize = 12, Margin = new Thickness(5, 0, 0, 0) };
slider.ValueChanged += (s, e) => valueText.Text = ((int)e.NewValue).ToString();
slider.PreviewMouseUp += async (s, e) =>
{
if (s is Slider sl && sl.Tag is string sn)
await setCommand(sn, (int)sl.Value);
};
row.Children.Add(slider);
row.Children.Add(valueText);
return row;
}
private StackPanel CreateInputRow(int? currentInput, List<InputSourceOption> options, string serialNumber)
{
var row = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) };
row.Children.Add(new TextBlock { Text = "Input", Foreground = Brushes.LightGray, Width = 70, FontSize = 12, VerticalAlignment = VerticalAlignment.Center });
var combo = new ComboBox { Width = 170, ItemsSource = options, DisplayMemberPath = "Name", Tag = serialNumber };
if (currentInput.HasValue)
combo.SelectedItem = options.Find(o => o.Value == currentInput.Value);
combo.SelectionChanged += async (s, e) =>
{
if (s is ComboBox cb && cb.Tag is string sn && cb.SelectedItem is InputSourceOption opt)
await CMMCommand.SetInputSource(sn, opt.Value);
};
row.Children.Add(combo);
return row;
}
private StackPanel CreatePowerRow(string status, string serialNumber)
{
var row = new StackPanel { Orientation = Orientation.Horizontal, Margin = new Thickness(0, 3, 0, 3) };
row.Children.Add(new TextBlock { Text = "Power", Foreground = Brushes.LightGray, Width = 70, FontSize = 12, VerticalAlignment = VerticalAlignment.Center });
var btn = new Button { Content = status, Width = 170, Tag = serialNumber };
btn.Click += async (s, e) =>
{
if (s is Button b && b.Tag is string sn)
{
var current = await CMMCommand.GetMonPowerStatus(sn);
if (current == "Sleep" || current == "PowerOff")
await CMMCommand.PowerOn(sn);
else
await CMMCommand.Sleep(sn);
await Task.Delay(1000);
b.Content = await CMMCommand.GetMonPowerStatus(sn);
}
};
row.Children.Add(btn);
return row;
}
}