如何防止在.NET中的表单初始化时触发值更改事件?

时间:2010-06-30 15:40:01

标签: .net winforms events

考虑一个简单的.NET表单,其中包含几个单选按钮和一个复选框。

每个单选按钮都有一个CheckedChanged处理程序设置,可根据复选框的状态执行某些操作。

我的问题是,当我初始化要检查的默认单选按钮时(从设计器属性窗口),该单选按钮会触发CheckedChanged事件,但Checkbox尚未初始化,所以我得到一个空指针异常或处理程序中使用了错误的值。无论哪种方式,我都不希望运行处理程序代码,除非用户在表单加载后选择一个单选按钮。

我目前通过不初始化单选按钮来解决这个问题,但我最终需要设置默认值,最好的位置来自设计师。我还可以添加一个布尔字段,在表单完全加载之前不会设置为true,如果是错误则不处理事件,但这是一个肮脏的黑客。

如何防止该处理程序运行其代码?

10 个答案:

答案 0 :(得分:28)

为了让它感觉稍微脏一点,如果你在表单的构造函数中初始化控件,你可以使用表单IsHandleCreated属性而不是你自己的bool来检查它是否应该实际验证。
我认为通常你不想在它第一次显示之前验证任何东西,并且在它出现之前不会创建句柄。

代码示例:

Private Sub myRadioButton_CheckedChanged(sender As Object, e As EventArgs) Handles myRadioButton.CheckedChanged
If myRadioButton.Checked AndAlso myRadioButton.IsHandleCreated Then
    'Do Work
End If
End Sub

答案 1 :(得分:20)

“我也可以在表单完全加载之前放置一个未设置为true的布尔字段,如果错误则不处理事件,但这是一个肮脏的黑客。”

这也是最简单和最好的方法!

让我们说.NET提供了一种简洁的方法来打开和关闭所有事件处理程序,直到加载表单。即使只是你正在处理的那些。它仍然不够灵活,无法禁用您想要启用的功能,但禁用您没有启用的功能。通常表单设置发生,您希望事件触发。如果没有事件触发,表单也无法正确构建。

答案 2 :(得分:3)

简单的解决方案是声明一个初始化变量:

  Private Initializing as boolean = True

  Private Sub rb_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles rbNuevos.CheckedChanged, RbDesaparecidos.CheckedChanged, RbModificados.CheckedChanged, RbNoDesap.CheckedChanged, RbDesHoy.CheckedChanged, RbChT.CheckedChanged
      if Initializing then return

      'Your Code    
  End Sub

  Public Sub New()

       ' Llamada necesaria para el Diseñador de Windows Forms.
       InitializeComponent()    
       ' Agregue cualquier inicialización después de la llamada a InitializeComponent().

       initializing = false
  end sub

最复杂:从方法中删除“句柄”,并在新方法上使用AddHandler

  Public Sub New()

       ' Llamada necesaria para el Diseñador de Windows Forms.
       InitializeComponent()    
       ' Agregue cualquier inicialización después de la llamada a InitializeComponent().

       AddHandler RbChT.CheckedChanged, AddressOf rb_CheckedChanged
  end sub

答案 3 :(得分:2)

对于Private Sub myNumeric_ValueChanged(sender As Object, e As EventArgs) Handles myNumeric.ValueChanged If myNumeric.Value >= 0 AndAlso myNumeric.IsHandleCreated Then 'Do the work End If End Sub ,请参阅Hans Olsson answer

对于数字向上,请按照这样做

myNumeric.Value

关键字为IsHandleCreatedThread

答案 4 :(得分:1)

另一种方式:

Private Sub dgvGroups_CellValueChanged(sender As System.Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvGroups.CellValueChanged

    If Me.Visible = False Then Exit Sub ' Sub gets called on form load which causes problems

    wksGroups.Cells(e.RowIndex + 1, 1) = dgvGroups.Item(e.ColumnIndex, e.RowIndex).Value
    wksGroups.Cells(1, 5) = dgvGroups.RowCount

答案 5 :(得分:0)

我发现有一件事情是在加载表单后手动添加事件。

要执行此操作,您只需进入该表单的设计器文件中找到的生成的表单代码,然后拉出添加该事件的行。它看起来像这样:

this.controlName.CheckedChanged += new System.EventHandler(this.controlName_CheckedChanged);

然后将所有这些调用放入在窗体构造函数中调用InitializeComponent之后调用的方法中。

答案 6 :(得分:0)

以防任何人仍在搜索此事件时,在初始化表单时触发事件但是表单尚未可见,并且说您有一个外键关系,在该关系上您需要一个默认值的问题行也更新。所以以下代码对我有用....

    if (Visible && !(e.ColumnIndex == 0))
        {
            phoneEdited = true;
            MessageBox.Show("A Phone entry has been entered");
        }

答案 7 :(得分:0)

  1. 不要在设计师真正做太多的控件上设置检查。
  2. 需要的全局标志和条件退出。
  3. 尝试。抓住疼痛部位,忽略无意义的异常。
  4. (使用VS 2017)在我看来,这是一个烦恼,但不是一个错误。它与使用的模型一致。该事件是由代码的正常操作引发的,但代码我没有写(但可以访问傻瓜害怕踩到的地方)以及在正常流程中早期似乎没有(正常)位置预测它的地方。

    最干净的答案似乎是,如果触发任何重要代码,则根本不检查设计器中的单选按钮或复选框控件。相反,这些控件应该在Load事件(例如)完成所有初始化之后通过代码(例如checked = true)进行更改。

    这里没有灵活性的损失,因为两者都是在构建之前修复的,只是在不同的地方。事件处理程序将处理它,就像用户在精心设计的GUI应用程序的自然流程中单击控件一样。 (这让我想起了古老的RPG谚语“不要贬低周期”。(这里的任何人都记得RPG吗?我,不是IBM面向团队的一员,从未使用它,但与一些人进行过有趣的讨论。)预检控件击中VS循环的错误部分。)

    如果出于任何原因无效,那么下一个最好的事情就是在其他地方建议的单一状态布尔值初始化为false,并在适当的时间设置为true,并在必要的位置使用条件退出以防止它们在此之前崩溃。它将完成工作,但它很难看。比失败更好。

    在我决定设计师级别的预设检查是问题之前我尝试过的另一件事是有一个非常可接受的替代方案是将危险点放在Try..Catch中以便能够忽略该异常。也是一个kludge。

答案 8 :(得分:-2)

也许对于某些功能,您可以使用click事件而不是check changed事件。

答案 9 :(得分:-4)

我在Module1文件中放了一个公共变量 Dim Public bolForm_LoadingTF as Boolean = True

在我提出的每个formLoad事件中 bolForm_LoadingTF = True

在每个具有OnSelectedIndexChanged的控件中 事件我把如果bolForm_LoadingTF = True然后退出Sub

在表格加载事件结束时我放了 bolForm_LoadingTF = False

我可能违反了一系列规则,但这有效 对我来说。