You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

继承实现问题:修改父类值如何同步到所有子类实例?

多实例状态指示器同步更新问题解决方案

问题背景

需要实现一个带文本和红/绿/黄圆点的状态指示器控件,要求在多个窗体中使用时,只要更新一次状态,所有实例都能同步反映变化。但当前实现中,调用单个实例的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 16:25:38