简体   繁体   中英

Visual Studio WinForms designer does not instantiate object

I created a class derived from System.Windows.Forms.ContextMenuStrip class, not as a user control, just a plain .cs class with a constructor and one event handler.

When I drag this class from the Toolbox onto the designer, it creates a private member for it and a couple of properties, but does not instantiate an object.

Thus, at runtime I get "Object reference not set to an instance of an object.", because the designer never generates the line:

this.searchGridContextMenu1 = new SearchGridContextMenu();

inside InitializeComponent.

It used to generate this line, as a matter of fact, I keep putting it back in from my Vault repository, but the designer just "eats it" again.

Update: I now tried creating a User Control using the same class and it has the same problem just doing that.

I cross-posted this comment on another question but since this is related here it is again.

When a User Control won't load into the Visual Studio designer here is what you need to do. These instruction are for vb.net project but c# should be similar. Also, before doing this close all open windows (or at least the source and designer files of the control you are working on.)

One last thing. The FIRST thing you should do is ensure that restarting visual studio doesn't fix the problem. If not you can try the steps that follow. These instructions assume that the errant user controls are in control library project in visual studio. If not you should be able to adjust the directions a bit to get it to work but it is much easier when the control is in its own project.

Do the following:

  1. Make the control library your startup project.
  2. Open the properties for the control library project and click on the debug tab.
  3. Under Start Action click the Start external program option and browse to the Visual Studio executable.

NOTE: what this means is that when you run your solution it will fire up another instance of Visual Studio instead of actually running your solution. The First Instance of Visual Studion (INSTANCE_1) will "host" a second instance of visual studio (INSTANCE_2) when you run it.

  1. Run your solution. INSTANCE_2 will load.
  2. Switch back to INSTANCE_1.
  3. In INSTANCE_1 hit CTRL-ALT-E. This will open up the exceptions dialog box. Check On the THROWN column checkbox next to Common Language Runtime Exceptions.

NOTE: This will ensure that INSTANCE_1 will BREAK at ANY runtime error even if it is hit in a try block.

  1. Switch to INSTANCE_2. In Solution Explorer double-click to open the errant user control.

You should find that INSTANCE_1 OF Visual Studio should have stopped at the line of code that caused the designer to not load the control. Fix the code (which usually means testing for IsNot Nothing before references an object properties...but could mean other things.)

Also, sometimes I find that the control WILL load in INSTANCE_2 instead of breaking on an error in INSTANCE_1. In that case just stop debugging...close INSTANCE_2. Save/Restart INSTANCE_1 and your problem will often have gone away.

The lesson is this. User Control MUST be able to load/reference all objects and their members in order to load it into the designer. So for User Controls that will be placed onto other containers I will usually design events to notify the parent rather than trying to push objects into the child control.

Hope this helps for future reference on this old question.

Seth

Did I read this right? Visual Studio deletes the line that constructs the instance of your control?

Is your constructor public? At some point I changed the accessibility of my constructor from public to internal - trying to be good, stop the pesky users from accessing things they shouldn't - but then I suffered from the same effects that you describe, I kept having to add my constructor back into InitializeComponent.

It took me months to realise my mistake...just kept thinking it was a bug in Visual Studio. Changed it back to public and no problems.

This problem occurs when InitializeComponent () crosses with base and inherited components. Solution is call the component's designer's method. Otherwise the base method will be called.

 public Form() { this.InitializeComponent(); // base.InitializeComponent <-- default one is thisone } 

Inheriting from the control isn't enough. This is the bare minimum that I had to implement to make it work:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WinForms
{
    class Foo : System.Windows.Forms.ContextMenuStrip
    {
        public Foo()
        {
            InitializeComponent();
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            base.OnPaint(pe);
        }

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            components = new System.ComponentModel.Container();
        }

        #endregion
    }
}

将无参数构造函数从内部更改为公共已解决了该问题

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM