65.9K
CodeProject 正在变化。 阅读更多。
Home

集中显示窗体验证逻辑

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (4投票s)

2005年5月17日

4分钟阅读

viewsIcon

31451

downloadIcon

364

本文将展示如何在打开 Windows 窗体时集中化逻辑。

引言

本文旨在向您展示一种在打开 Windows 窗体时集中化逻辑的简便方法。

背景

在开发 Windows 应用程序时,通常会希望执行某种类型的操作或验证,以确定是否可以打开某个窗体。许多时候,相同的代码需要在项目中的不同位置执行。显然,良好的设计不会在应用程序中重复堆砌相同的代码。那么,为什么不使用窗体的构造函数来在打开窗体之前执行任何操作或验证逻辑呢?在窗体中使用构造函数执行某些操作确实存在限制。例如,如果您有 FormA 并在构造函数中执行了所有安全验证,则没有任何东西可以阻止开发人员执行以下操作,并将窗体显示给用户:

FormA frm = new FormA();
FormA.Show();

在此示例中,在 FormA 构造函数中放入安全逻辑太早了,我们希望将该逻辑推迟到稍后。将其放入 Show() 方法将是窗体打开之前的最后时机。这样做还可以使您的代码更具防御性。

有人可能会问,为什么不将安全逻辑放入窗体的 ActivatedEnterLoad 事件中呢?在某些情况下,这样做是可以的,但这些事件的引发实际上暗示了窗体可能已显示给用户。如果要在所有前面提到的事件处理程序中都放置相同的逻辑,您的代码将不会很整洁。如果窗体因任何原因无法显示给用户,那么在事件引发之前停止进程会更简单。

假设

在提出此解决方案时,我做出了一些假设:

  1. 您正在处理的代码库有一个基窗体,项目中的所有窗体都从中继承。
  2. 构造函数用于初始化窗体的显示。
  3. 构造函数未用于执行任何将用于确定窗体是否将打开的逻辑。
  4. 构造函数未执行将提交给传递到窗体构造函数的任何对象的逻辑。这一点很重要,因为如果构造函数正在向传递到窗体构造函数的对象提交新状态,并且在调用 Show()ShowDialog() 方法时窗体不会打开,那么您将处于一个不太理想的境地。

解决方案

为了解决这个问题,我们将仅使用关键字 new 来重写项目基窗体 (BaseForm) 中 Show()ShowDialog() 的基类实现。派生的 Windows 窗体无法重写 Show()ShowDialog() 方法,因此我们将使用关键字 new 重写这些方法,插入我们自己的逻辑,然后调用基类方法。

public new virtual DialogResult ShowDialog() {
     if (CanOpenForm)
          return base.ShowDialog();

     ShowFormError();
     return DialogResult.None;
}

public new virtual DialogResult ShowDialog(IWin32Window owner) {
     if (CanOpenForm)
          return base.ShowDialog(owner);

     ShowFormError();
     return DialogResult.None;
}

public new virtual void Show() {
     if (CanOpenForm) {
          base.ShowDialog();
     } else {
          ShowFormError();
          return;
     }
}

protected virtual bool CanOpenForm {
     get {
          ///preform general validation logic for opening all forms here.
          return true;
     }
}

protected virtual void ShowFormError() {
     ShowFormError("Form could not be opened.");
}

protected virtual void ShowFormError(string sErrorMessage) {
     ShowFormError(sErrorMessage, "Form Open Error", 
                 MessageBoxButtons.OK, MessageBoxIcon.Error);
}

protected virtual void ShowFormError(string sErrorMessage, string sCaption, 
     MessageBoxButtons buttons, MessageBoxIcon icon) {

     MessageBox.Show(sErrorMessage, sCaption, buttons, icon);
}

现在让我们回顾一下上面的代码。Show()ShowDialog() 方法都在调用基类方法之前检查 CanOpenForm 属性。您可以选择为每个 Show()ShowDialog() 方法设置不同的 CanOpenForm 属性,但更有可能的是使用相同的属性就足够了。请注意,CanOpenForm 属性已设为虚拟,这样所有派生窗体都可以重写此属性并添加窗体特定的验证。另请注意,我已将 Show()ShowDialog() 设为虚拟,以便您可以完全重写派生窗体上的验证逻辑。

请注意,在重写 ShowDialog() 时,如果 CanOpenForm 失败,则具体返回 DialogResult.None。这是因为 base.ShowDialog() 默认返回 DialogResult.None。如果用户按下了模式对话框窗体右上角的“X”,将返回 DialogResult.Cancel。我们不希望返回该值,因为它会暗示对话框窗体可能已显示给用户,而实际上并未显示。

您还可以做另一件很酷的事情,那就是确保窗体被正确打开。例如,假设您的项目有一个 BaseForm 和一个继承自 BaseFromBaseDialogFormBaseDialogForm 用于所有其他将继承自它的模式窗体(带有 OK 和 Cancel 按钮)。由于这是一个模式窗体,您可能希望重写 Show() 方法。

public override void Show() {
     System.Diagnostics.Debug.Assert(false, 
               "All Dialog Box Forms should be modal.");
     base.Show();
}

在重写基类 Show() 方法时,我只是向开发人员发送了一个调试断言,说明不应使用此方法。尽管该方法仍然调用 base.Show(),但其实现并非过于突兀。您有许多其他选择:

  1. 强制执行,通过调用 System.Diagnostics.Debug.Fail 或根本不调用任何方法。
  2. 强制重写的 Show() 方法调用 ShowDialog()
  3. 其他任何事情,都没有硬性规定,怎么方便怎么来。
© . All rights reserved.