代码之家  ›  专栏  ›  技术社区  ›  CodeFusionMobile

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

  •  19
  • CodeFusionMobile  · 技术社区  · 14 年前

    考虑一个简单的.NET窗体,它有几个单选按钮和一个复选框。

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

    我的问题是,当我在要检查的默认RadioButton上初始化时(从Designer属性窗口),将为该单选按钮激发CheckedChanged事件,但该复选框尚未初始化,因此我要么得到空指针异常,要么在处理程序中使用了错误的值。不管怎样,我都不希望处理程序代码运行,除非用户在加载表单后选择一个单选按钮。

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

    我该怎么做才能阻止该处理程序运行其代码?

    10 回复  |  直到 6 年前
        1
  •  20
  •   FastAl    7 年前

    我还可以放置一个布尔字段,该字段在窗体完全加载之前不设置为true,如果设置为false,则不处理事件,但这是一个肮脏的黑客行为。

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

    假设.NET提供了一种简洁的方法,可以在加载表单之前关闭所有事件处理程序。即使只是你处理的那些。它仍然没有足够的灵活性来禁用您想要启用的,但是禁用您没有启用的。通常会发生窗体设置,并且您希望触发事件。同样,如果 事件发生了。

        2
  •  28
  •   Brent Hans Olsson    11 年前

    为了使它稍微不那么脏,如果您在表单的构造函数中初始化控件,您可能可以使用表单 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
    
        3
  •  3
  •   Peter Mortensen icecrime    12 年前

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

      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
    
        4
  •  2
  •   Community CDub    8 年前

    为了 radiobutton 看见 Hans Olsson answer

    对于数字上下,请这样做

    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
    

    关键字是 myNumeric.Value IsHandleCreated

        5
  •  1
  •   Kristian    11 年前

    另一种方式:

    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
    
        6
  •  0
  •   Zach    12 年前

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

    要做到这一点,您只需进入在该表单的设计器文件中找到的生成表单代码,并拉出添加事件的行。它看起来像这样:

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

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

        7
  •  0
  •   Jeff    8 年前

    为了防止任何人仍在搜索此项,初始化表单时将激发事件,但表单尚不可见,还应说明您有一个外键关系,在此关系上,您有一个默认值所需的问题,该问题也将在每行更新时激发。所以下面的代码对我有效……

        if (Visible && !(e.ColumnIndex == 0))
            {
                phoneEdited = true;
                MessageBox.Show("A Phone entry has been entered");
            }
    
        8
  •  0
  •   RDeLisle    6 年前
    1. 不要在一个在设计器中真正起作用的控件上设置checked。
    2. 全局标志和条件在需要时退出。
    3. 尝试..抓住痛点忽略一个毫无意义的异常。

    (使用vs 2017)在我看来,这是一个烦恼,但不是一个错误。与使用中的模型一致。事件是由代码的正常操作触发的,但我没有编写代码(但可以访问愚人害怕踩踏的地方),并且在正常流的前面似乎没有(合适的)位置来预测它。

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

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

    如果出于任何不起作用的原因,下一个最好的方法是在其他地方建议使用kludge,在适当的时间将单个状态布尔值初始化为false并设置为true,在必要的位置设置条件出口,以防止它们崩溃。它能完成任务,但很难看。总比失败好。

    另一件事是,在我决定设计师级别的预先设置检查是问题所在,还有一个非常可接受的选择,就是把危险点放在一个尝试中..捕获可以忽略异常。也是一个笨蛋。

        9
  •  -2
  •   JaJa    11 年前

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

        10
  •  -4
  •   Harold Clements    11 年前

    我在module1文件中放入了一个公共变量 dim public bolForm_loadingtf as boolean=true

    在每次窗体加载事件中 BolForm_Loadingtf=真

    在每个控件中,OnSelectedIndexChanged 如果BolForm_Loadingtf=true,则输入事件I,然后退出Sub

    在窗体加载事件结束时 bolForm_loadingtf=假

    我可能违反了一系列的规则,但这行得通 为了我。