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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3150882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 14:27:52  来源:igfitidea点击:

How to prevent value changed events from firing on form initialization in .NET?

.netwinformsevents

提问by CodeFusionMobile

Consider a simple .NET form with a couple of radio buttons and a checkbox.

考虑一个带有几个单选按钮和一个复选框的简单 .NET 表单。

Each of the radio buttons has a CheckedChanged handler setup that performs some action based on the state of the checkbox.

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

My problem is, when I initialize on the default radiobutton to be checked (from the designer properties window) the CheckedChanged event is fired for that radio button, but the Checkbox hasn't been initialized yet so I either get a null pointer exception or the wrong value is used in the handler. Either way, I don't want that handler code to be run unless the user picks a radio button after the form has been loaded.

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

I currently get around this by not initializing the radio button, but I need to set that default eventually and the best place is from the designer. I also can add a boolean field that's not set to true until the form is fully loaded and not process the events if that is false, but it's a dirty hack.

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

What can I do to prevent that handler from running its code?

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

回答by Hans Olsson

To make it feel slightly less dirty, if you initialize the controls in the constructor of the form you might be able to use the forms IsHandleCreatedproperty rather than your own bool to check if it should actually validate or not.
I would think that normally you wouldn't want to validate anything before it's been shown for the first time and handle isn't created until it is.

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

Code Example:

代码示例:

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

回答by FastAl

"I also can put a boolean field that's not set to true until the form is fully loaded and not process the events if that is false, but it's a dirty hack."

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

It's also the easist and best way to do it!

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

Lets say .NET provides a neat way to turn an and off all the event handlers until the form is loaded. Even just the ones YOU are handling. It would still not be sufficiently flexible to disable what you wanted to enable but disable what you didn't. Often form setups happen and you want the events to fire. Also the form won't build right if noevents fire.

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

回答by x77

The easy solution is to declare an initializing variable:

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

  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

Most sophisticated: Remove the "handles" from the method, and use AddHandleron the new method.

最复杂的:从方法中删除“句柄”,并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

回答by Cary Bondoc

For radiobuttonsee Hans Olsson answer

对于radiobutton汉斯·奥尔森回答

For numeric up down, do it like this

对于数字向上向下,这样做

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

The keyword is myNumeric.Valueand IsHandleCreated

关键字是myNumeric.ValueIsHandleCreated

回答by Kristian

Yet another way:

还有一种方式:

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

回答by Jeff

Just in case anyone is still searching for this the event is fired upon initializing the form BUT the form is not yet visible, Also Say that you have a foreign key relationship upon which you have a default value needed issue that gets fired every row update too. So the following code worked for me....

以防万一有人仍在搜索此事件,在初始化表单时会触发该事件,但该表单尚不可见,另外假设您有一个外键关系,在该关系上您有一个需要默认值的问题,该问题也会在每行更新时触发. 所以下面的代码对我有用....

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

回答by RDeLisle

  1. Don't set checked on a control that really does much in designer.
  2. The global flag and conditional exits where needed.
  3. Try..Catch the sore spots to ignore a meaningless exception.
  1. 不要在设计器中真正发挥作用的控件上设置选中状态。
  2. 全局标志和条件在需要时退出。
  3. 尝试..抓住痛点以忽略无意义的异常。

(Using VS 2017) It appears to me that it is an annoyance but not a bug. It is consistent with the model in use. The event is fired by normal operation of code, but code I did not write (but can access where fools fear to tread) and where there appears to be no (decent) place earlier in the normal flow to anticipate it.

(使用 VS 2017)在我看来,这是一个烦恼,但不是一个错误。它与使用的模型一致。该事件是由代码的正常操作触发的,但是我没有编写的代码(但可以访问傻瓜害怕踏入的地方)以及在正常流程中早期似乎没有(体面的)地方来预测它的地方。

The cleanest answer seems to be not to check radio button or checkbox controls in the designer at all if they trigger any significant code. Instead these controls should be changed by code (e.g. checked = true) in the Load event (for example) AFTER all the initialization is done.

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

There is no loss of flexibility here since both are fixed before the build, only in different places. The event handlers will handle it exactly as if a user had clicked the control in the natural flow of a well designed GUI application. (This reminds me of the ancient RPG proverb "Don't buck the cycle". (Anyone here remember RPG? I, not part of IBM-oriented team, never used it but had interesting discussions with some who did. ) Pre-checking controls hits the wrong part of the VS cycle.)

这里没有失去灵活性,因为两者在构建之前都是固定的,只是在不同的地方。事件处理程序将处理它,就像用户在设计良好的 GUI 应用程序的自然流程中单击控件一样。(这让我想起了古老的 RPG 谚语“Don't buck the cycle”。(这里有谁记得 RPG 吗?我不是面向 IBM 的团队的一员,从未使用过它,但与一些使用过的人进行了有趣的讨论。)控件击中了 VS 循环的错误部分。)

If for any reason that will not work, the next best thing is the kludge suggested elsewhere of a single status boolean initialized false and set true at the appropriate time with conditional exits in the necessary places to prevent them from crashing until then. It will get the job done, but it's ugly. Better than failure.

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

Another thing I tried before I decided that designer level pre-set checks were the problem and there was a very acceptable alternative was to put the danger spots in a Try..Catch to be able to ignore the exception. Also a kludge.

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

回答by Zach

One thing I've found that works is adding the events manually after you load the form.

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

To do this you can simply go into the generated form code found in the designer file of that form, and pull out the lines that add the event. It would look something like this:

为此,您可以简单地进入在该表单的设计器文件中找到的生成的表单代码,并拉出添加事件的行。它看起来像这样:

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

Then put all of these calls into a method that you call after the InitializeComponent call in your form's constructor.

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

回答by JaJa

Maybe for some functionality you can use the click event instead of the check changed event.

也许对于某些功能,您可以使用单击事件而不是检查更改事件。

回答by Harold Clements

I put a public variable in the Module1 file Dim Public bolForm_LoadingTF as Boolean = True

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

In each formLoad event I put bolForm_LoadingTF = True

在每个 formLoad 事件中,我都将 bolForm_LoadingTF = True

In each control with an OnSelectedIndexChanged event I put if bolForm_LoadingTF = True then Exit Sub

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

At the end of the form load event I put bolForm_LoadingTF = False

在表单加载事件结束时,我将 bolForm_LoadingTF = False

I am probably breaking a bunch of rules but this works for me.

我可能违反了很多规则,但这对我有用。