0

I have a custom component for use in winforms which works well. There is only one small problem, when I drop it on a form the designer does not inserts it into the components collection, like it does for all other components.

When I drop a contextmenuitem or a bindingsource on a form, these are included in the components collection, but my user component is not. I suspect I need to put some exotic attribute in the declaration of the component but I do not have a clue what that might be.

Maybe someone out here knows how to do this ?

heres the complete code of the component

public partial class ggDataBase : Component
{
    private string _ConnectionString = "";
    private SqlConnection connection = new SqlConnection();
    private SqlDataAdapter adapter = new SqlDataAdapter();
    private SqlCommand command = new SqlCommand();

    public string ConnectionString
    {
        get { return _ConnectionString; }
        set { _ConnectionString = value; }
    }

    public void FillDataTable(DataTable Table, string SqlText)
    {
        if ((connection.ConnectionString == null) || (connection.ConnectionString != _ConnectionString))
            connection.ConnectionString = _ConnectionString;

        if (connection.ConnectionString != null && connection.ConnectionString != "")
        {
            if (command.Connection == null)
                command.Connection = connection;
            command.CommandText = SqlText;
            command.CommandType = CommandType.Text;
            adapter.SelectCommand = command;
            adapter.Fill(Table);
        }
    }
}
GuidoG
  • 11,359
  • 6
  • 44
  • 79

1 Answers1

1

Not sure where you're going wrong...it works for me with your exact code. I also created a blank component and added it as well:

Components dropped onto the Form

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication110
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
    }

    public partial class MyComponent : Component
    {

    }


    public partial class ggDataBase : Component
    {
        private string _ConnectionString = "";
        private SqlConnection connection = new SqlConnection();
        private SqlDataAdapter adapter = new SqlDataAdapter();
        private SqlCommand command = new SqlCommand();

        public string ConnectionString
        {
            get { return _ConnectionString; }
            set { _ConnectionString = value; }
        }

        public void FillDataTable(DataTable Table, string SqlText)
        {
            if ((connection.ConnectionString == null) || (connection.ConnectionString != _ConnectionString))
                connection.ConnectionString = _ConnectionString;

            if (connection.ConnectionString != null && connection.ConnectionString != "")
            {
                if (command.Connection == null)
                    command.Connection = connection;
                command.CommandText = SqlText;
                command.CommandType = CommandType.Text;
                adapter.SelectCommand = command;
                adapter.Fill(Table);
            }
        }
    }

}

Here's an example designer file. Note that the components are declared and instantiated, but you will NOT see any of them (not even the built-in .Net components) explicitly being added to the "components" collection:

partial class Form1
{
    /// <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 Windows Form 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()
    {
        this.components = new System.ComponentModel.Container();
        this.myComponent1 = new WindowsFormsApplication111.MyComponent(this.components);
        this.button1 = new System.Windows.Forms.Button();
        this.ggDataBase1 = new WindowsFormsApplication111.ggDataBase();
        this.timer1 = new System.Windows.Forms.Timer(this.components);
        this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
        this.bindingSource1 = new System.Windows.Forms.BindingSource(this.components);
        ((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).BeginInit();
        this.SuspendLayout();
        // 
        // button1
        // 
        this.button1.Location = new System.Drawing.Point(55, 62);
        this.button1.Name = "button1";
        this.button1.Size = new System.Drawing.Size(75, 23);
        this.button1.TabIndex = 0;
        this.button1.Text = "button1";
        this.button1.UseVisualStyleBackColor = true;
        this.button1.Click += new System.EventHandler(this.button1_Click);
        // 
        // ggDataBase1
        // 
        this.ggDataBase1.ConnectionString = "";
        // 
        // contextMenuStrip1
        // 
        this.contextMenuStrip1.Name = "contextMenuStrip1";
        this.contextMenuStrip1.Size = new System.Drawing.Size(61, 4);
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(284, 261);
        this.Controls.Add(this.button1);
        this.Name = "Form1";
        this.Text = "Form1";
        ((System.ComponentModel.ISupportInitialize)(this.bindingSource1)).EndInit();
        this.ResumeLayout(false);

    }

    #endregion

    private MyComponent myComponent1;
    private System.Windows.Forms.Button button1;
    private ggDataBase ggDataBase1;
    private System.Windows.Forms.Timer timer1;
    private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
    private System.Windows.Forms.BindingSource bindingSource1;

}

And here's the output showing that the components were actually added (even yours):

WindowsFormsApplication111.MyComponent
System.Windows.Forms.Button
WindowsFormsApplication111.ggDataBase
System.Windows.Forms.Timer
System.Windows.Forms.ContextMenuStrip
System.Windows.Forms.BindingSource

That was generated by this code:

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

    private void button1_Click(object sender, EventArgs e)
    {
        foreach(Component C in EnumerateComponents())
        {
            Console.WriteLine(C.GetType().ToString());
        }
    }

    // http://stackoverflow.com/a/17173320/2330053
    private IEnumerable<Component> EnumerateComponents()
    {
        return from field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
               where typeof(Component).IsAssignableFrom(field.FieldType)
               let component = (Component)field.GetValue(this)
               where component != null
               select component;
    }

}

Please see my previous comment with the link in it. Here's the article again:

A component can let the designer know that it would like to be notified when its container goes away by implementing a public constructor that takes a single argument of type IContainer, as shown in this snippet. ... Notice that the constructor uses the container to add itself as a container component. In the presence of this constructor, the designer will generate code that uses this constructor, passing it a container for the component to add itself to.

Since you didn't provide that constructor, I can only guess that this is being done for you by the base class constructor. But I assure you, even though you don't have a line like that with components being passed in, your component is indeed being added to the collection. Look at the output from the previous code I posted above.

Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
  • Its really not that hard to see what I mean, in the designer.cs components like the timer are created like this: this.timer1 = new Timer(THIS.COMPONENTS) while ggDataBase is created as this.ggDataBase1 = new ggDataBase() which means that timer1 is created and added to the components collection and ggDataBase1 is not – GuidoG Jan 08 '15 at 22:43
  • in other words, timer1 is EXPLICIT added to the components collection and ggDataBase1 is not – GuidoG Jan 08 '15 at 22:44
  • Dude, seriously? You're not reading very well. Your ggDataBase was added to the components collection. **Look at the output generated by the code in the Button handler above.** It is right below the example designer file I posted. Your component is clearly listed in there along with all the other components. This was generated at **run-time**. How else do you suppose it got there?... – Idle_Mind Jan 08 '15 at 22:49
  • But apart from that, I did not know this EnumarateComponents trick in your code and yes that one does indeed returns all components and even all controls where as looping throug the components collection does not. So you have helped me after all and I will accept your answer after all – GuidoG Jan 08 '15 at 22:50
  • For clarity, you do not have to have that type of line in the designer file. If you don't, it is handled by the **base** Component class, that you **inherited** from. – Idle_Mind Jan 08 '15 at 22:50
  • Dude, seriously, the code clearly shows new ggDataBase() with no arguments. If you do foreach (Component in components) then ggDataBase1 will not be in there while timer1 is in there. You are using a different method of looping through all components and your method does returns ggDataBase1 while my method did not. You did not anwser my question but you did gave me a very good workaround which I can use – GuidoG Jan 08 '15 at 22:54
  • How are you getting "timer1" in the output?...I'm not. Not even with `C.ToString()`. – Idle_Mind Jan 08 '15 at 22:58
  • Well I be damned, the timer does indeed not showup in the list, while all other components are... Looks more like black magic to me than internal magic – GuidoG Jan 08 '15 at 23:01
  • got it, the timer was on the base form and had its modifier still on private in stead of protected. Now it also appears in the list – GuidoG Jan 08 '15 at 23:03
  • LoL...but does it show up as "timer1" (with a numeric digit on the end), or just "Timer"? If I put two Timers on the form they are both just listed as generic Timers. Glad the posting was helpful in some way. – Idle_Mind Jan 08 '15 at 23:08
  • No they do not show up like that. This cannot be done because a Timer is inherited from Component and Component does not have a Name property for some unknown reason. It shows like this "System.Windows.Forms.Timer" – GuidoG Jan 08 '15 at 23:13