通知模态框的父级需要执行某项操作

3
我有一个父表单打开一个模态表单,它基本上允许用户更改应用程序的数据库设置。 当用户在模态(子)表单上单击保存按钮时,它将使用新设置保存Settings对象,但我需要让主表单检查数据库设置是否正确。 我目前是通过一个函数来实现的,该函数尝试简单地连接到数据库,并在成功时返回true,如果失败则返回false。我在应用程序的构造函数中执行该函数,因此每次关闭和重新启动应用程序时都会运行良好。 我尝试在保存设置后的模态表单中尝试以下操作,但会收到关于myManager对象的NullReference异常。 这是一个获取新设置并保存它们,然后尝试调用父表单的CheckDatabaseIsSetup()公共函数以测试数据库连接的功能。
/// <summary>
    /// Save the settings and then hide the Settings window
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btn_Save_Click(object sender, EventArgs e)
    {            
        // TRUE: User indicates that we are to connect using a trusted connection
        // FALSE: User wants to use Integrated security to connect.
        if (rb_UseTrustedConnection.Checked)
        {

            AppSettings.DatabaseName = tb_Trusted_DbName.Text;
            AppSettings.Server = tb_Trusted_Server.Text;
            AppSettings.UseIntergratedSecurity = false;
        }
        else
        {
            AppSettings.DatabaseName = tb_Secure_DbName.Text;
            AppSettings.Server = tb_Secure_Server.Text;
            AppSettings.Username = tb_Secure_Username.Text;
            AppSettings.Password = tb_Secure_Password.Text;
            AppSettings.UseIntergratedSecurity = true;
        }

        try
        {             
            AppSettings.SaveSettings();
            BushBreaksLodgeManagerMain myManager = (BushBreaksLodgeManagerMain)this.ParentForm;
            myManager.CheckDatabaseIsSetup();
        }
        catch (Exception ex)
        {
            log.LogAppendWithException(ex);
        }

        this.Hide();
    }

为什么不把CheckDatabaseIsSetup()的代码放进某种设置管理器类中,然后你可以从任何想要的地方调用它。表单中的代码应与UI相关。 - Ben Robinson
Ben,抱歉我应该提到主窗体的函数CheckDatabaseIsSetup()调用了databaseutilities类的TestDatabaseConnection来测试连接。因此它在一个单独的对象中。我将调用放在主函数中的原因是允许主窗体在连接失败时打开数据库设置窗体。 - John Cogan
4个回答

1
最好在子窗体中定义一个事件,并在主窗体中处理此事件,每当您在子窗体中引发此事件时,主窗体可以执行自己的工作。

1
BushBreaksLodgeManagerMain myManager = (BushBreaksLodgeManagerMain)this.ParentForm;

您可以检查上面的代码行,看看ParentForm是否为类型/可转换为BushBreaksLodgeManagerMain。我猜测这种情况不成功,因此返回null


1

通常我会使用对象间通信,例如使用我的Emesary库;设计的思路是使用通知的方式发送请求,并由任何知道需要处理这些通知的东西来处理它们,因此例如添加额外的事件处理程序是很容易的,而且不会影响其他部分。

在这种情况下,检查数据库设置的代码将变为:

if (ReceiptStatus.OK == 
    GlobalNotifier.NotifyAll(new CheckDatabaseIsSetupNotification(tb_Secure_DbName.Text,
                             tb_Secure_Server.Text,
                             tb_Secure_Username.Text,
                             tb_Secure_Password.Text,
                             true))
{
     // do something.
}
要使此功能正常工作,您需要在BushBreaksLodgeManagerMain中实现IReceiver,并在构造函数中调用它。
    GlobalTransmitter.Register(this);

然后实现接口 receive:

public ReceiptStatus Receive(INotification _message)
{
    if (_message is CheckDatabaseIsSetupNotification)
    {
         var message = _message as CheckDatabaseIsSetupNotification;
         if (connect_to(message.DatabaseName, message.Server, Message.Username, message.Password, message.UseIntergratedSecurity))
            return ReceiptStatus.OK;
         else
            return ReceiptStatus.Fail;
    }
    return ReceiptStatus.NotProcessed;
}

您可以使用Windows事件来实现此操作,但这种方式更清晰,并允许与不一定具有窗口的对象进行交互。


1

您应该使用模态窗体中的Owner属性,而不是ParentForm属性,具体如下:

BushBreaksLodgeManagerMain myManager = (BushBreaksLodgeManagerMain)this.Owner;

Owner属性定义了拥有的(模态)窗体和父级(拥有者)窗体之间的实际关系。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,