【问题标题】:Is it possible for a closed form's events to fire?关闭表单的事件是否有可能触发?
【发布时间】:2015-02-20 00:57:14
【问题描述】:

我从 FrmDelivery 调用“查找”表单。 Find 表单在尝试将条形码扫描到编辑框中时崩溃(相同的代码在应用程序的其他地方也可以正常工作,例如在 FrmDelivery 中)。

日志文件显示 FrmDelivery 是遇到异常的表单:

Message: Reached frmDelivery.StartRead

Date: 2/19/2015 7:39:39 PM
Message: From FrmDelivery.StartRead(): The scanner not enabled, Call Enable() first.; Inner Ex: ; Stack Trace:    at 
Symbol.Barcode.Actions.Read(ReaderData rd)

然而,在打开 Find 表单之前,我关闭了 FrmDelivery(下面的“this”):

private void buttonFind_Click(object sender, EventArgs e)
{
    ExceptionLoggingService.Instance.WriteLog("Reached frmDelivery.buttonFind_Click");
    this.Close(); // Close the Delivery form; this still leaves frmMain up
    const HHSConsts.RecordTypes rt = HHSConsts.RecordTypes.Delivery;
    frmFind ff = new frmFind(rt, dsdName);
    ff.ShowDialog();
}

StartRead() 是抛出异常的方法:

private void StartRead()
{
    ExceptionLoggingService.Instance.WriteLog("Reached 
frmDelivery.StartRead");
    try
    {
        // If we have both a reader and a reader data
        if ((this.barcodeReader != null) && (this.barcodeReaderData != 
null)) 
        {
            if (this.barcodeReaderData.IsPending) return;
            // Submit a read
            this.barcodeReader.ReadNotify += this.barcodeEventHandler;
            this.barcodeReader.Actions.Read(this.barcodeReaderData);
        }
    }
    catch (Exception ex)
    {
        String msgInnerExAndStackTrace = String.Format(
                "{0}; Inner Ex: {1}; Stack Trace: {2}", ex.Message, 
ex.InnerException, ex.StackTrace);
        ExceptionLoggingService.Instance.WriteLog(String.Format("From 
FrmDelivery.StartRead(): {0}", msgInnerExAndStackTrace));
    }
}

// StartRead() 在 FrmDelivery 的四个地方被调用:

private void textBoxUPC_PLU_GotFocus(object sender, EventArgs e)
{
    textBoxUPC_PLU.BackColor = HHSConsts.BARSCAN_COLOR; // Why is this
not sticking?
    ExceptionLoggingService.Instance.WriteLog("Reached
frmDelivery.textBoxUPC_PLU_GotFocus");
    if (this.InitReader())
    {
        this.StartRead();
    }
}

private void BarcodeReader_ReadNotify(object sender, EventArgs e)
{
    ExceptionLoggingService.Instance.WriteLog("Reached
frmDelivery.BarcodeReader_ReadNotify");
    try
    {
        Symbol.Barcode.ReaderData TheReaderData =
this.barcodeReader.GetNextReaderData();

        if (TheReaderData.Result == Symbol.Results.SUCCESS)
        {
            // Handle the data from this read
            this.HandleData(TheReaderData);
            // Start the next read
            this.StartRead();
        }
    }
    catch (Exception ex)
    {
        String msgInnerExAndStackTrace = String.Format(
                "{0}; Inner Ex: {1}; Stack Trace: {2}", ex.Message,
ex.InnerException, ex.StackTrace);
        ExceptionLoggingService.Instance.WriteLog(String.Format("From
FrmDelivery.BarcodeReader_ReadNotify(): {0}",
msgInnerExAndStackTrace));
    }
}

private void ReaderForm_Activated(object sender, EventArgs e)
{
    ExceptionLoggingService.Instance.WriteLog("Reached
frmDelivery.ReaderForm_Activated");
    // If there are no reads pending on barcodeReader, start a new read
    if (!this.barcodeReaderData.IsPending)
    {
        this.StartRead();
    }
}

private void textBoxId_GotFocus(object sender, EventArgs e)
{
    ExceptionLoggingService.Instance.WriteLog("Reached
frmDelivery.textBoxId_GotFocus");
    if (this.InitReader())
    {
        this.StartRead();
    }
}

但是在表单关闭后,任何方法如何调用 StartRead()?

【问题讨论】:

  • 我很困惑:你说Find表单崩溃了,但是日志摘录似乎说frmDelivery是源,也说是第一个代码块中关闭的表单。无论如何,frmDelivery 也是一个对话框吗?
  • 是的,这就是我的问题 - 为什么关闭表单的事件会触发? FrmDelivery 通过 ShowDialog() 从 frmMain 调用;使用 ShowDialog() 从 FrmDelivery 调用 frmFind。
  • 旁注:this.barcodeReader.ReadNotify += this.barcodeEventHandler; 看起来很麻烦,因为它似乎会多次添加此事件处理程序。这可能会使该方法运行多次。
  • @LarsTech:那么将代码移到构造函数中会更好,还是在连接处理程序之前先解开处理程序(-=)?

标签: c# forms barcode barcode-scanner scanning


【解决方案1】:

...这些方法中的任何一个如何在表单关闭后调用 StartRead()?

这取决于。条形码阅读器对象还在吗? IE。它被任何东西引用了吗?

关闭一个表单会做两件事之一,这取决于它是否是模态的:隐藏窗口(对于模态窗口),或关闭并释放窗口(对于非模态窗口)。这几乎是您可以保证的全部内容(不包括您添加的其他逻辑,例如 FormClosed 事件处理程序)。

特别是,关闭表单不会以任何方式本身导致该对象被垃圾收集或以其他方式禁用。许多表单仅由 Winforms 框架引用,当关闭时,这些引用将被丢弃。但是,如果您做任何事情导致您的表单在其他地方被引用,它将继续存在。

您的FrmDelivery 表单似乎订阅了条形码阅读器对象的ReadNotify 事件。这涉及将委托实例添加到事件的调用列表中,并且由于事件处理程序方法是实例方法,因此该委托实例包含对 FrmDelivery 对象的引用。

只要条形码阅读器对象仍然可以访问(或者如果它是static 类,因此它的所有成员始终可以访问),这意味着您的FrmDelivery 对象也仍然可以访问。也就是说,条形码阅读器对象保留了委托对象,而委托对象又引用了FrmDelivery 对象。

由于您的事件处理程序方法实际上是您的StartRead() 方法可以被调用的方法之一,因此很可能这实际上就是正在发生的事情。您的代码示例中没有足够的上下文,任何阅读它的人都无法确定,但概率非常高。这将是一个不错的选择。 :)


顺便说一句,除了事件处理程序订阅(从问题描述看来,它似乎会让FrmDelivery 对象保持活动状态),您似乎正在以一种的方式嵌套您的ShowDialog() 调用> 会阻止FrmDelivery 对象被收集。

具体来说:您在表单上的按钮的事件处理程序中调用FrmDelivery 对象上的Close()。在该处理程序中的ShowDialog() 方法调用返回之前,该处理程序不会返回,并且在该处理程序返回之前,您对FrmDelivery 窗口的原始ShowDialog() 调用无法返回,并且在该ShowDialog() 调用返回之前,该方法的调用者无法处理或以其他方式丢弃表单实例。

这与是否调用事件处理程序本身无关,但它确实对对象的生命周期有影响。

【讨论】:

    猜你喜欢
    • 2011-10-04
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-23
    • 2011-05-05
    • 1970-01-01
    相关资源
    最近更新 更多