是否有可能触发封闭形式的事件?

Is it possible for a closed form's events to fire?

我从 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)

然而,在打开“查找”表单之前,我关闭了 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()?

…how could any of these methods call StartRead() after the form has been closed?

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

关闭表单会执行以下两项操作之一,具体取决于它是否为模态:隐藏 window(对于模态 windows),或关闭并处理 window (对于非模态windows)。这几乎就是您可以保证的全部内容(不包括您添加的其他逻辑,例如 FormClosed 事件处理程序)。

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

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

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

由于您的事件处理程序方法实际上是可以调用您的 StartRead() 方法的方式之一,因此这很可能就是实际发生的情况。您的代码示例中没有足够的上下文让阅读它的人绝对确定,但可能性非常高。这是一个不错的选择。 :)


顺便说一句,除了事件处理程序订阅(从问题描述来看,它看起来无论如何都会使 FrmDelivery 对象保持活动状态),您似乎正在以 [=46] 的方式嵌套 ShowDialog() 调用=]也会阻止收集FrmDelivery对象。

具体来说:您在表单按钮的事件处理程序中的 FrmDelivery 对象上调用 Close()。在该处理程序 return 中调用 ShowDialog() 方法之前,该处理程序不会 return,并且在处理程序 return 之前,您最初的 ShowDialog() 调用 FrmDelivery window 不能 return,并且在 ShowDialog() 调用 return 之前,该方法的调用者不能处理或丢弃表单实例.

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