跨WinForm同步LED状态问题:静态变量方案失效求助
WinForm跨窗体LED状态同步问题解决方案
我看了你的代码,问题主要出在两个地方:Form2根本没读取静态类Led的状态,而且即使静态变量变化了,Form2也不会自动触发重绘更新LED。咱们一步步来修复:
问题分析
- Form2的
OnPaint方法里用的是自己的私有字段isGreen,完全没用到你定义的Led.isGreen静态变量,这就导致Form1的状态变化根本传不过来。 - 就算你改成读取
Led.isGreen,Form2也不会主动知道变量变化,除非强制触发重绘。
修复步骤
1. 升级静态Led类,添加状态变化事件
我们给静态类加一个事件,当isGreen变化时通知订阅者,这样Form2就能及时收到状态更新:
public static class Led { private static bool _isGreen; // 定义状态变化事件 public static event Action<bool> IsGreenChanged; public static bool IsGreen { get => _isGreen; set { if (_isGreen != value) { _isGreen = value; // 触发事件,通知所有订阅者 IsGreenChanged?.Invoke(value); } } } }
2. 修正Form1的状态设置逻辑
原来Form1里直接给字段赋值,现在改成用属性,这样才会触发事件:
public class Form1 : Form { // ... 其他代码不变 ... protected override void OnPaint(PaintEventArgs args) { base.OnPaint(args); try { Nuitrack.Update(_skeletonTracker); } catch (LicenseNotAcquiredException exception) { Console.WriteLine("LicenseNotAcquired exception. Exception: ", exception); throw exception; } catch (Exception exception) { Console.WriteLine("Nuitrack update failed. Exception: ", exception); } args.Graphics.DrawImage(_bitmap.Bitmap, new Point(0, 0)); Pen blackPen = new Pen(Color.Black, 5); args.Graphics.DrawEllipse(blackPen, 565, 403, 50, 50); // 先默认设为红色 args.Graphics.FillEllipse(Brushes.Red, 565, 403, 50, 50); Led.IsGreen = false; if (_skeletonData != null && _skeletonData.Skeletons.Length > 0) { // 检测到骨骼,设为绿色 args.Graphics.FillEllipse(Brushes.Green, 565, 403, 50, 50); Led.IsGreen = true; } } }
这里还优化了判断逻辑:只有当骨骼数组不为空且有元素时才设为绿色,避免遍历空数组的冗余操作。
3. 让Form2订阅状态变化并更新LED
在Form2的构造函数里订阅Led.IsGreenChanged事件,并且修正OnPaint方法读取静态类的状态,同时处理线程安全(因为Nuitrack的更新可能在非UI线程):
public class Form2 : Form { // ... 其他代码不变 ... public Form2() { // 注意你原来的构造函数写的是FormPrincipale,应该改成Form2 InitializeComponent(); // 订阅LED状态变化事件 Led.IsGreenChanged += OnLedStateChanged; } private void OnLedStateChanged(bool isGreen) { // WinForm控件必须在UI线程更新,所以检查是否需要Invoke if (InvokeRequired) { Invoke(new Action<bool>(OnLedStateChanged), isGreen); return; } // 触发重绘 Invalidate(); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Pen blackPen = new Pen(Color.Black, 5); e.Graphics.DrawEllipse(blackPen, 615, 513, 40, 40); // 直接读取静态类的状态来绘制LED if (Led.IsGreen) { e.Graphics.FillEllipse(Brushes.Green, 615, 513, 40, 40); } else { e.Graphics.FillEllipse(Brushes.Red, 615, 513, 40, 40); } } // 记得在Dispose里取消订阅,避免内存泄漏 protected override void Dispose(bool disposing) { if (disposing) { Led.IsGreenChanged -= OnLedStateChanged; components?.Dispose(); } base.Dispose(disposing); } }
另外注意你原来的Form2构造函数名称写错了,应该是public Form2()而不是FormPrincipale,这会导致窗体无法正常初始化,这个小问题也要修正。
为什么原来的方法不生效?
- 你在Form2的
OnPaint里用的是自己的isGreen字段,和静态类Led完全无关,所以Form1的状态变化根本不会影响到它。 - 就算你改成读取
Led.isGreen,Form2的OnPaint只会在窗体初始化、大小变化等默认触发重绘的场景下执行,不会因为静态变量变化自动刷新,所以需要通过事件触发Invalidate()来强制重绘。
这样修改后,Form2的LED就会和Form1的LED同步,检测到骨骼时一起变绿,未检测到时变回红色啦。
内容的提问来源于stack exchange,提问作者guido pastore
相关产品推荐
相关产品推荐

