开发者

c# form inheritance event handlers fire twice

开发者 https://www.devze.com 2022-12-17 11:57 出处:网络
I inherit from a root form that has a next and back button in, then use these buttons on some subforms and get the buttons called twice, i beleive the problem to be outlined in the MSDN here:

I inherit from a root form that has a next and back button in, then use these buttons on some subforms and get the buttons called twice, i beleive the problem to be outlined in the MSDN here: http://msdn.microsoft.com/en-us/library/e33683a5(VS.71).aspx

how would i apply the advice they give to C# rather than VB?

It is causing lots of problems having all my buttons called twice, thanks.

Code:

Root Form

public partial class rootForm : Form
    {
        public rootForm()
        {
            InitializeComponent();
        }

        private void rootForm_Load(object sender, EventArgs e)
        {
            //used for all generic strings e.g. buttons
            this.Text = Resources.UIStrings.FormTitle.ToString();
            this.btnNext.Text = Resources.UIStrings.btnNext.ToString();
            this.btnBack.Text = Resources.UIStrings.btnBack.ToString();
        }

From designer:

        // btnNext
        // 
        this.btnNext.DialogResult = System.Windows.Forms.DialogResult.Cancel;
        resources.ApplyResources(this.btnNext, "btnNext");
        this.btnNext.Name = "btnNext";
        this.btnNext.UseVisualStyleBackColor = true;

Install Form

from designer

        // 
        // btnNext
        // 
        this.btnNext.Location = new System.Drawing.Point(373, 360);
        this.btnNext.Size = new System.Drawing.Size(99, 23);
        this.btnNext.TabIndex = 7;
        this.btnNext.Text = "Install";
        this.btnNext.Click += new System.EventHandler(this.installButton_Click);

From Form:

    private void installButton_Click(object sender, EventArgs e)
    {
     doSomeStuff();
    }

Call Stack from VS for BOTH times the event is called

Installer.exe!Installer.InstallerForm.installButton_Click(object sender = {Text = "Siguiente"}, System.EventArgs e = {X = 21 Y = 10 Button = Left}) Line 226    C#

    [External Code] 

Installer.exe!Installer.Program.Main() Line 21 + 0x1d bytes C#

[External Code] 

Edit2 tracing the callstack back with a breakpoint gives:

myInstaller.exe!myInstaller.InstallerForm.installButton_Click
[Native to Managed Transition]
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Control.OnClick
System.Windows.Forms.dll!System.Windows.Forms.Button.OnClick
System.Windows.Forms.dll!System.Windows.Forms.Button.OnMouseUp
System.Windows.Forms.dll!System.Windows.Forms.Control.WmMouseUp
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc
System.Windows.Forms.dll!System.Windows.Forms.ButtonBase.WndProc
System.Windows.Forms.dll!System.Windows.Forms.Button.WndProc
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback
[Native to Managed Transition]
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop
System.Windows.Forms.dll!System.Windows.Forms.Application.Run
myInstaller.exe!myInstaller.Program.Main
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context
mscorlib.dll!System.Threading.ExecutionContext.Run
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart
 ******************* Function: myInstaller.InstallerForm.installButton_Click(object, System.EventArgs), Thread: 0xE00 Main Thread

myInstaller.exe!myInstaller.InstallerForm.installButton_Click
[Native to Managed Transition]
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Control.OnClick
System.Windows.Forms.dll!System.Windows.Forms.Button.OnClick
System.Windows.Forms.dll!System.Windows.Forms.Button.OnMouseUp
System.Windows.Forms.dll!System.Windows.Forms.Control.WmMouseUp
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc
System.Windows.Forms.dll!System.Windows.Forms.ButtonBase.WndProc
System.Windows.Forms.dll!System.Windows.Forms.Button.WndProc
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback
[Native to Managed Transition]
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop
System.Windows.Forms.dll!System.Windows.Forms.Application.Run
myInstaller.exe!myInstaller.Program.Main
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context
mscorlib.dll!System.Threading.ExecutionContext.Run
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart
 ******************* Function: myInstaller.InstallerForm.installButton_Click(objec开发者_JAVA百科t, System.EventArgs), Thread: 0xE00 Main Thread

If i attach to the designer section where the handler is added i get

myInstaller.exe!myInstaller.InstallerForm.InitializeComponent
myInstaller.exe!myInstaller.InstallerForm.InstallerForm
myInstaller.exe!myInstaller.WelcomeForm.btnNext_Click
System.Windows.Forms.dll!System.Windows.Forms.Control.OnClick
System.Windows.Forms.dll!System.Windows.Forms.Button.OnClick
System.Windows.Forms.dll!System.Windows.Forms.Button.OnMouseUp
System.Windows.Forms.dll!System.Windows.Forms.Control.WmMouseUp
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc
System.Windows.Forms.dll!System.Windows.Forms.ButtonBase.WndProc
System.Windows.Forms.dll!System.Windows.Forms.Button.WndProc
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback
[Native to Managed Transition]
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop
System.Windows.Forms.dll!System.Windows.Forms.Application.Run
myInstaller.exe!myInstaller.Program.Main
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context
mscorlib.dll!System.Threading.ExecutionContext.Run
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart
 ******************* Function: myInstaller.InstallerForm.InitializeComponent(), Thread: 0xA34 Main Thread

myInstaller.exe!myInstaller.InstallerForm.InitializeComponent
myInstaller.exe!myInstaller.InstallerForm.performChecks
myInstaller.exe!myInstaller.InstallerForm.InstallerForm
myInstaller.exe!myInstaller.WelcomeForm.btnNext_Click
System.Windows.Forms.dll!System.Windows.Forms.Control.OnClick
System.Windows.Forms.dll!System.Windows.Forms.Button.OnClick
System.Windows.Forms.dll!System.Windows.Forms.Button.OnMouseUp
System.Windows.Forms.dll!System.Windows.Forms.Control.WmMouseUp
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc
System.Windows.Forms.dll!System.Windows.Forms.ButtonBase.WndProc
System.Windows.Forms.dll!System.Windows.Forms.Button.WndProc
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback
[Native to Managed Transition]
[Managed to Native Transition]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop
System.Windows.Forms.dll!System.Windows.Forms.Application.Run
myInstaller.exe!myInstaller.Program.Main
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context
mscorlib.dll!System.Threading.ExecutionContext.Run
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart
 ******************* Function: myInstaller.InstallerForm.InitializeComponent(), Thread: 0xA34 Main Thread

But this shouldn't be as it looks like the form is getting created twice? but if i put a breakpoint on the installerform creator it is only called once.


could you add some code of how do you inherit and use buttons? In C# you should not have a such issue, because there is no Handles keyword.

You may, however, add multiple time handlers to the buttons event click like:

parent
    myButton.Click += myClickAction

child
    sameButton.Click += sameClickAction

When inheriting you should not click on the inherited buttons in designer(that will add a new, maybe the same, action on the inherited button)

Add a breackpoint in the twice executed action, when hit consult the CallStack Visual Studio Window in order to see who calls your method twice...

EDIT

Not sure what happens, but try the following:

Replace:

this.btnNext.Click += new System.EventHandler(this.installButton_Click);

with

this.btnNext.Click -= new System.EventHandler(this.installButton_Click);
this.btnNext.Click -= new System.EventHandler(this.installButton_Click);
this.btnNext.Click -= new System.EventHandler(this.installButton_Click);
this.btnNext.Click += new System.EventHandler(this.installButton_Click);

EDIT2

In order to analyze the calls to your method instantly do the following:

  1. Set a Tracepoint in the installButton_Click method: alt text http://lh4.ggpht.com/_1TPOP7DzY1E/S13KtR6tpYI/AAAAAAAAC9s/GpCZpXEukv4/s800/3setBreackpoint.png

  2. Edit the tracepoint properties, in order to trace the callstack(or also use just $CALLER - only theprevious function): alt text http://lh6.ggpht.com/_1TPOP7DzY1E/S13KtE98okI/AAAAAAAAC9o/gW5TfXouQDM/s800/2brackpoint.png

  3. In the Output window deactivate(right click) all messages but "Program Output";

  4. Analyze your output in run-time:

alt text http://lh4.ggpht.com/_1TPOP7DzY1E/S13Ks9YHEHI/AAAAAAAAC9k/WgnO5cBtUxI/s800/1output.png


C# adds event handlers to controls this way.

this.btnMyButton.Click += new System.EventHandler(this.btnMyButton_Click);

Just take a look if you have something like the statement above for your button within the derived form, if so, remove/comment it, since it is adding an additional event handler for that button.


If you don't resolve it yet try remove creation (+=) of the event in the inherited form and let the event method only (button_click). In example below I've created a button which is using in the inherited form and its behaviour is different there but no fire event from base:

FormA : Form 
{
   ...
   protected System.Windows.Forms.Button buttonBase = new System.Windows.Forms.Button();
   this.buttonBase.Click += new System.EventHandler(this.buttonBase_Click);

   protected virtual void buttonBase_Click(object sender, EventArgs e)
   {
       MessageBox.Show("Hi from base", "Hello");
   }
}

FormB : FormA
{
   ...
   // comment or remove line below, othervise you'll see "Hi from inherited form" twice
   // this.buttonBase.Click += new System.EventHandler(this.buttonBase_Click);         

   protected override void buttonBase_Click(object sender, EventArgs e)
   {
       MessageBox.Show("Hi from inherited form", "Elo");
   }
}


when you created form B as inherited from a base form A then all events defined in form A are automatically active in your inherited form B.

If in your form B you add an event then both base A form's event and your new B form's event will be called - first base form's event then your B form's event.

if you want to "override" that is disable base A form's event you should: 1) change A form's event's declaration from private to protected (so that your B form can see it) 2) open B's form constructor and subtract that event with -=


During adding data to database table when I click on the add button then automatically firing twice time and using this code the problem was solved.

public void addEmployee(object sender, EventArgs e)
                {

    controlsAdd.addBtn.Click -= new EventHandler(controlsAdd.addEmpInfToTable);
    controlsAdd.upDateBtn.Click -= new EventHandler(controlsAdd.updateEmployee); 
    controlsAdd.deleteBtn.Click -= new EventHandler(controlsAdd.deleEmployee);

     splitContainer1.Panel2.Controls.Clear();
     controlsAdd.AddControls(splitContainer1);


                }

Reference:https://learn.microsoft.com/en-us/dotnet/framework/winforms/controls/how-to-add-to-or-remove-from-a-collection-of-controls-at-run-time

0

精彩评论

暂无评论...
验证码 换一张
取 消