0

我需要对多线程编程模型进行一些澄清,因为我很少需要处理它(大部分时间我都在做网络编程)。

来路

我有一个我用 C# 编写的程序,基本上它是一个数据监视器,并在数据库上执行每个特定的时间量,比如 1 分钟。

这个应用程序是如何相对简单的,我决定使用一个整体结构,我制作了类范围内的所有 GUI,我制作了一个处理连接和数据检索的对象。

为了处理池时间的要求,我使用了 a System.Timers.Timer,它基本上是一个带有触发定时事件的 Thread 包装,在这里我执行了数据池。

当找到新数据时,我需要从定时器触发的函数(根据定义在其他线程中)触发属于 GUI(现在在主线程中运行)的 X 类中的方法。

第一次尝试直接调用定时器触发的方法,导致跨线程错误:因为方法驻留在X类中,没有在定时器线程中构造。

然后我再次尝试使用其他方法。我在类中使用他各自的委托创建了一个事件,该委托读取数据并将 GUI 对象订阅到该事件。

问题

现在,当我触发事件时,.net 会产生一个异常,告诉我发送者对象实例为空,完全不知道为什么,但我怀疑这是因为对象本身是使用主线程中的 GUI 对象创建的,当我决定从另一个线程发送对象(它正在生成事件),实例根本不存在,因为没有在那里创建。

这是计时器到期时调用的函数:

    private void PoolearMensajes(object Sender, ElapsedEventArgs e)
    {
        try
        {
            pRdr.getPendingMessages(); <--- This function creates the exception
            if (pRdr.MensajesPendientes > 0)
            {
                this.oSysIcon.Text = pRdr.MensajesPendientes.ToString() + " tickets pendientes";
                this.oSysIcon.BalloonTipIcon = ToolTipIcon.Info;
                this.oSysIcon.BalloonTipText = pRdr.MensajesPendientes.ToString() + " tickets pendientes";
                this.oSysIcon.BalloonTipTitle = "Información";
                this.oSysIcon.ShowBalloonTip(3000);
                System.Media.SystemSounds.Exclamation.Play();
            }
        }
        catch (Exception ex)
        {
            this.oSysIcon.BalloonTipTitle = "Error";
            this.oSysIcon.Text = "Ha ocurrido un error.";
            this.oSysIcon.BalloonTipIcon = ToolTipIcon.Error;
            this.oSysIcon.BalloonTipText = ex.Message;
            this.oSysIcon.ShowBalloonTip(3000);
            System.Media.SystemSounds.Exclamation.Play();
        }
    }

这是驻留在主线程中创建的数据检索器对象中的方法:

    public delegate void TicketsFoundHandler(object sender, TicketEventArgs ta);
    public event TicketsFoundHandler TicketsFound;

    public void getPendingMessages()
    {
        string sSQL;
        sSQL = " an SQL Query that counts rows;";
        oCmd = new SqlCommand(sSQL, oConn);
        oConn.Open();
        this.i_pendmsg = (int)oCmd.ExecuteScalar();
        if (this.i_pendmsg > 0)
        {
            TicketEventArgs ta = new TicketEventArgs("", this.i_pendmsg);
            TicketsFound(this, ta); <---- ERROR!
        }
        oConn.Close();
    }

错误消息是:Object reference not set to an instance of an object

任何想法,任何改进,或者我没有考虑过的东西?

4

1 回答 1

2

第一次尝试直接调用定时器触发的方法,导致跨线程错误:因为方法驻留在X类中,没有在定时器线程中构造。

你快到了。您只需要调用BeginInvoke()即可在 GUI 线程上调用您的操作。

您可能还会发现使用 aBackgroundWorker更加容易。

编辑:

您在问题中的具体错误是因为没有人订阅您的TicketsFound活动。用于TicketsFound += ...这样做。此外,在引发事件之前检查 null:

if (TicketsFound != null) TicketsFound(...)
于 2012-10-31T16:45:50.037 回答