views:

818

answers:

2

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(object, 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.

+3  A: 

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

  2. Edit the tracepoint properties, in order to trace the callstack(or also use just $CALLER - only theprevious function): alt text

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

  4. Analyze your output in run-time:

alt text

serhio
added some code, I can't see a repeated handler and a search turned up nothing.
Nathan
Ok the call stack shows this: MynetInstaller.exe!MynetInstaller.InstallerForm.installButton_Click(object sender = {Text = "Siguiente"}, System.EventArgs e = {X = 60 Y = 9 Button = Left}) Line 226 C#both times, so both times its called by the button with text "Siguiente" (next)?
Nathan
yes, but see the next caller, who does cal the Button "Siguiente"?...
serhio
i'm not exactly sure how to see, i've not used this part of VS much, how would I do that? thanks
Nathan
i get that line above, then[external code]Installer.exe!Installer.Program.Main() Line 21 + 0x1d bytes[external code]And get identical entries both times it is called
Nathan
Thanks Serhio, It stops when I add that change, but will only run the button once even if you generate a new click event. but a passable work around, does this point to an underlying reason for thie behaviour?
Nathan
Apparently somewhere in the code you subscribe twice to your event. The multiple `-=` unsubscribe multiple instances, and adds only one, but, normally, you should add a tracepoint(breackpoint with a 'when hit..' condition) and correct the code do not add twice the same handler to this Click event.
serhio
hmmm would a search have no turned up the second subscription? leaving it 'as is' is a bit annoying as whenever you open the form it raises a warning that the underlying code has been changed and that this could cause problems! How would a breakpoint help? thanks for all your help
Nathan
you can see my Edit2
serhio
thats again for your help, i've done as you recommended but they both seem identical?
Nathan
ok, they are really identical, could you now move the same tracepoint at the `this.btnNext.Click +=` line and paste the trace?
serhio
done - results added to OP
Nathan
as you ca see, the difference is in the `InstallerForm.performChecks` function(called in InitializeComponent?). So, perhaps it adds the second time the handler.Its better anyway to move all initialization custom logic (as `performChecks`) from `InitializeComponent` to `OnLoad` or `_Load` in the form.
serhio
Perfect, i removed those sections and its solved, the code only runs once! Thank you for your help serhio, i owe you one!
Nathan
you welcome, pleased to help.
serhio
A: 

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.

Albert
I have looked and can't see one, i have also done a search for this.btnMyButton_Click in my project and found a single reference.
Nathan
search `btnNext.Click` and `btnMyButton_Click` (without `this.`)
serhio
the only reference is in designer as i've shown above, (one in each of the three different subforms inherited from "rootForm" )
Nathan