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

C#队列管理系统:实现静态表单实时显示更新叫号数据

队列管理系统实时显示解决方案

核心解决思路

  1. 单例模式保证显示表单唯一:禁止外部直接实例化FrmDisplay,通过静态方法获取唯一实例,彻底解决重复创建问题。
  2. 事件驱动实现解耦更新:用全局事件类分离工作站叫号逻辑与显示逻辑,工作站只负责发布更新事件,显示表单自动响应刷新。
  3. 优化数据存储结构:用字典替代多个独立静态变量,适配更多工作站且维护成本更低。

代码实现

1. 单例模式改造FrmDisplay

public partial class FrmDisplay : Form
{
    private static FrmDisplay _instance;
    private static readonly object _lockObj = new object();

    // 私有构造函数,禁止外部直接实例化
    private FrmDisplay()
    {
        InitializeComponent();
        // 订阅叫号更新事件
        QueueDataManager.TicketUpdated += OnTicketUpdated;
    }

    // 获取唯一实例的线程安全方法
    public static FrmDisplay GetInstance()
    {
        lock (_lockObj)
        {
            if (_instance == null || _instance.IsDisposed)
            {
                _instance = new FrmDisplay();
            }
            return _instance;
        }
    }

    // 处理叫号更新事件,跨线程刷新UI
    private void OnTicketUpdated(string workstationName, string ticketNumber)
    {
        if (InvokeRequired)
        {
            Invoke(new Action<string, string>(OnTicketUpdated), workstationName, ticketNumber);
            return;
        }

        // 根据工作站名称更新对应控件,示例用switch适配多个工作站
        switch (workstationName)
        {
            case "Ght1":
                lblGht1.Text = ticketNumber;
                break;
            case "Ght2":
                lblGht2.Text = ticketNumber;
                break;
            case "Ght3":
                lblGht3.Text = ticketNumber;
                break;
            case "Ght4":
                lblGht4.Text = ticketNumber;
                break;
            case "Ght5":
                lblGht5.Text = ticketNumber;
                break;
        }
    }
}

2. 全局队列数据管理类(事件驱动)

public static class QueueDataManager
{
    // 存储各工作站当前叫号,支持动态新增工作站
    public static Dictionary<string, string> CurrentTickets { get; } = new Dictionary<string, string>();

    // 叫号更新事件,所有订阅者会收到通知
    public static event Action<string, string> TicketUpdated;

    // 对外暴露的叫号更新方法
    public static void UpdateTicket(string workstationName, string ticketNumber)
    {
        if (CurrentTickets.ContainsKey(workstationName))
        {
            CurrentTickets[workstationName] = ticketNumber;
        }
        else
        {
            CurrentTickets.Add(workstationName, ticketNumber);
        }

        // 触发事件,通知所有订阅者(比如FrmDisplay)
        TicketUpdated?.Invoke(workstationName, ticketNumber);
    }
}

3. 工作站表单叫号按钮逻辑改造

private void btnCallTicket_Click(object sender, EventArgs e)
{
    string ticketNumber = lblNumApl.Text;
    string workstationName = lblSessionpostetravail.Text;

    // 执行语音合成
    var speechSynthesizer = new SpeechSynthesizer();
    speechSynthesizer.SpeakAsync($"Ticket numéro {ticketNumber}, {workstationName}");

    // 发布叫号更新事件,自动同步到显示表单
    QueueDataManager.UpdateTicket(workstationName, ticketNumber);

    // 确保显示表单处于可见状态
    var displayForm = FrmDisplay.GetInstance();
    if (!displayForm.Visible)
    {
        displayForm.Show();
    }
    else
    {
        displayForm.BringToFront();
    }
}

关键注意事项

  • 跨线程UI更新:SpeakAsync是异步操作,事件可能在非UI线程触发,必须用Invoke确保UI更新在主线程执行,避免异常。
  • 扩展性:新增工作站时,只需在FrmDisplay的switch中添加对应分支,或直接用控件名称与工作站名称绑定的方式(比如控件命名为lbl_工作站名,通过反射直接查找控件),无需修改其他逻辑。
  • 资源释放:如果需要关闭FrmDisplay,建议改为隐藏(Hide()),避免实例被销毁后下次需要重新创建。

内容的提问来源于stack exchange,提问作者Eloge28

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 01:32:48