继承实现问题:修改父类值如何同步到所有子类实例?
多实例状态指示器同步更新问题解决方案
问题背景
需要实现一个带文本和红/绿/黄圆点的状态指示器控件,要求在多个窗体中使用时,只要更新一次状态,所有实例都能同步反映变化。但当前实现中,调用单个实例的SetText方法时,只有该实例会更新,其他实例无变化。
问题根源
当前每个StatusIndicator实例都是独立存储自身状态,没有共享的统一数据源。修改单个实例的状态不会通知其他实例,因此无法实现同步更新。要解决这个问题,需要引入共享状态模型+事件通知机制,让所有实例监听同一个状态源的变化,自动同步UI。
修改方案
1. 创建共享状态模型
用静态类实现全局共享的状态存储,并定义状态变化事件,用于通知所有实例更新:
public static class StatusIndicatorSharedState { // 状态变化通知事件 public static event Action<string, StatusIndicatorBase.status> OnStatusChanged; private static string _currentText = string.Empty; private static StatusIndicatorBase.status _currentStatus = StatusIndicatorBase.status.green; // 更新全局状态并触发通知 public static void UpdateStatus(string text, StatusIndicatorBase.status status) { _currentText = text; _currentStatus = status; OnStatusChanged?.Invoke(text, status); } // 获取当前全局状态,用于实例初始化同步 public static (string Text, StatusIndicatorBase.status Status) GetCurrentStatus() { return (_currentText, _currentStatus); } }
2. 修改基类StatusIndicatorBase
让基类订阅共享状态的变化事件,自动同步UI;同时修改SetText方法,改为更新全局状态而非自身状态:
public class StatusIndicatorBase : Panel { public Brush indicatorColor; public SolidBrush redBrush = new SolidBrush(Color.Red); public SolidBrush greenBrush = new SolidBrush(Color.Green); public SolidBrush yellowBrush = new SolidBrush(Color.Yellow); public Label indicatorText = new Label() { AutoSize = false, BackColor = Color.Transparent }; public int indicatorBorderSize = 1; public int indicatorSize = 20; public int marginSize = 8; public enum status { red, green, yellow }; public StatusIndicatorBase() { // 订阅全局状态变化事件 StatusIndicatorSharedState.OnStatusChanged += OnSharedStatusUpdated; // 初始化时同步当前全局状态 var (text, currentStatus) = StatusIndicatorSharedState.GetCurrentStatus(); UpdateSelfUI(text, currentStatus); } // 全局状态变化时,更新当前实例UI private void OnSharedStatusUpdated(string message, status currentStatus) { UpdateSelfUI(message, currentStatus); } // 对外暴露的更新方法,实际更新全局状态 public void SetText(string message, status currentStatus) { StatusIndicatorSharedState.UpdateStatus(message, currentStatus); } // 内部更新当前实例UI的方法,处理跨线程问题 private void UpdateSelfUI(string message, status currentStatus) { if (InvokeRequired) { Invoke(new Action<string, status>(UpdateSelfUI), message, currentStatus); return; } int oldWidth = TextRenderer.MeasureText(indicatorText.Text, indicatorText.Font).Width; indicatorText.Text = message; int newWidth = TextRenderer.MeasureText(indicatorText.Text, indicatorText.Font).Width; indicatorText.Width = newWidth; indicatorText.Top = (Height - indicatorText.Height) / 2; // 修正垂直居中计算 Width = indicatorText.Width + indicatorSize + marginSize; // 避免文本与圆点重叠 Location = new Point(Location.X + (oldWidth - newWidth), Location.Y); SetColor(currentStatus); Refresh(); } public string GetText() { return indicatorText.Text; } public void SetColor(status currentStatus) { switch (currentStatus) { case status.green: indicatorColor = greenBrush; break; case status.red: indicatorColor = redBrush; break; case status.yellow: indicatorColor = yellowBrush; break; } } protected override void OnPaint(PaintEventArgs e) { Graphics g = e.Graphics; Pen pen = new Pen(Color.Black, indicatorBorderSize); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; int size = indicatorSize - indicatorBorderSize * 2; // 调整圆点位置,避免与文本重叠 int dotX = Width - indicatorSize - marginSize / 2; int dotY = (Height - size) / 2; g.DrawEllipse(pen, dotX, dotY, size, size); g.FillEllipse(indicatorColor, dotX, dotY, size, size); BringToFront(); } protected override void Dispose(bool disposing) { base.Dispose(disposing); // 取消订阅,防止内存泄漏 StatusIndicatorSharedState.OnStatusChanged -= OnSharedStatusUpdated; } }
3. 子类StatusIndicator调整
保留原有布局逻辑,无需额外修改:
public class StatusIndicator : StatusIndicatorBase { public StatusIndicator(int clientWidth, int clientHeight) { Height = indicatorSize; RightToLeft = RightToLeft.Yes; Location = new Point(clientWidth - indicatorSize - marginSize * 2, clientHeight - Height - marginSize); Anchor = AnchorStyles.Bottom | AnchorStyles.Right; Controls.Add(indicatorText); } }
修改后效果
现在无论调用哪个StatusIndicator实例的SetText方法,都会更新全局共享状态,所有订阅了事件的实例会自动同步更新UI,实现多窗体实例的状态统一。
内容的提问来源于stack exchange,提问作者Carlos M
相关产品推荐
相关产品推荐

