3

我从主表单打开了一个子表单,如下所示:

var cf = new ChildForm { Owner = this };
cf.Show();

然后子窗体在另一个线程上进行一些绘图。

当用户试图关闭主窗体时——如果子窗体已打开——则FormClosing首先触发一个事件ChildForm,然后在主窗体中引发相同的事件。在发生FormClosing事件时,子窗体停止其绘图线程。

当主窗体包含未保存的数据时,用户可能会尝试关闭主窗体。然后,主窗体的事件处理程序会向它们显示警告“数据未保存。取消关闭? ”。FormClosing然后他们可以取消保存(即主窗体的事件处理程序Cancel在对象上设置标志)。FormClosingEventArgsFormClosing

但是,到那时,子窗体的FormClosing事件已经被引发,并且它将停止其绘图线程。子窗体不知道它现在应该继续绘制(好像什么都没发生一样)。

是否可以从子窗体中检测到FormClosing事件已被主窗体取消?当用户被要求在主窗体中保存数据时,我仍然想停止重绘线程。

4

3 回答 3

2

我会提供一个基于接口的解决方案。如果应用程序可以关闭,您可以通过这种方式轻松管理统一的方式。通过以下实现,父窗体负责询问子窗口是否准备好关闭,子窗体执行必须执行的任何操作并回复主窗口。

假设我有接口IManagedForm

interface IManagedForm
{
    bool CanIBeClosed(Object someParams);
}

两种形式 (Form1ChildForm) 都会实现它。

请注意,对于此示例,我ChildForm以这种方式实例化:

ChildForm cf = new ChildForm() { Owner = this, Name = "ChildForm" };
cf.Show();

首先是接口的实现Form1

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    object someArgsInterestingForTheMethod = new object();

    e.Cancel = !((IManagedForm)this).CanIBeClosed(someArgsInterestingForTheMethod);
}

// Ask the ChildForm it is done. If not the user should not leave the application.
public bool CanIBeClosed(object someParams)
{
    bool isOKforClosing = true;

    var cf = this.Controls["ChildForm"] as IManagedForm;

    if (cf != null)
    {
        isOKforClosing = cf.CanIBeClosed(someParams);
        if (!isOKforClosing)
        {
            MessageBox.Show("ChildForm does not allow me to close.", "Form1", MessageBoxButtons.OK);
        }
    }
    return isOKforClosing;
}

最后你ChildForm的接口实现看起来像这样:

private void ChildForm_FormClosing(object sender, FormClosingEventArgs e)
{
    object someArgsInterestingForTheMethod = new object();

    e.Cancel = !((IManagedForm)this).CanIBeClosed(someArgsInterestingForTheMethod);
}

public bool CanIBeClosed(object someParams)
{
    // This flag would control if this window has not pending changes.
    bool meetConditions = ValidateClosingConditions(someParams);
    // If there were pending changes, but the user decided to not discard
    // them an proceed saving, this flag says to the parent that this form
    // is done, therefore is ready to be closed.
    bool iAmReadyToBeClosed = true;

    // There are unsaved changed. Ask the user what to do.
    if (!meetConditions)
    {
        // YES => OK Save pending changes and exit.
        // NO => Do not save pending changes and exit.
        // CANCEL => Cancel closing, just do nothing.
        switch (MessageBox.Show("Save changes before exit?", "MyChildForm", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
        {
            case DialogResult.Yes:
                // Store data and leave...
                iAmReadyToBeClosed = true;
                break;
            case DialogResult.No:
                // Do not store data, just leave...
                iAmReadyToBeClosed = true;
                break;
            case DialogResult.Cancel:
                // Do not leave...
                iAmReadyToBeClosed = false;
                break;
        }
    }
    return iAmReadyToBeClosed;
}

// This is just a dummy method just for testing
public bool ValidateClosingConditions(object someParams)
{
    Random rnd = new Random();
    return ((rnd.Next(10) % 2) == 0);
}

希望它足够清楚。

于 2012-07-03T08:49:49.347 回答
1

好吧,Yes/NO/Cancel 的决定性逻辑转移到了一些中心类。ChildParent
中的 任何一个FormClosing都调用相同的函数。

自然地,为了获得良好的用户体验,如果从两个FormClosing函数调用函数,则必须以仅执行一次事件的方式对其进行管理。

于 2012-07-03T06:38:24.093 回答
0

MSDN 将 FormClosing 事件解释为在窗体关闭之前调用的事件。继续说,对于 MDI,所有子窗体 FormClosing 事件都在调用父窗体 FormClosing 事件之前调用。

所以这意味着,当在主窗体上按下关闭按钮时,它会为所有子窗体引发 FormClosing 事件。所以子窗体应该判断它是否准备好关闭,并相应地设置取消属性。当为主窗体引发事件时,它应该已经设置为取消。

即使在主窗体上引发了关闭事件,主窗体也不应该决定子窗体。

如需进一步阅读,

MSDN 上 Form.FormClosing 事件的解释

解释如何使用取消属性

于 2012-07-03T07:06:39.873 回答