Sunday, September 7, 2008

Add, Delete and Move controls at runtime.


In this article you will learn how to:
· Add or delete controls at runtime.
· Access controls with the indexer.
· Create control collection using Hash Table.

Download full source code.
To start with, create a windows application project and add a class to it. We will create a button array so name it as “ButtonArray.cs”.

Add the following code to it:

using System;
using System.Collections;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ManageControls
{
public delegate void SendSelectedButton(object sender);
public class ButtonArray : Hashtable
{
private readonly Form HostForm;
public event SendSelectedButton SelectedButton;
Point buttonLocation;
int cntButton = 0;

public ButtonArray(Form host)
{
HostForm = host;
}

public void AddButton(int left, int top)
{
Button btnElement = new Button();

btnElement.Top = top;
btnElement.Left = left;
btnElement.Tag = cntButton;
btnElement.Cursor = System.Windows.Forms.Cursors.Default;
btnElement.FlatStyle = System.Windows.Forms.FlatStyle.System;
btnElement.Text = "Button " + cntButton.ToString();
btnElement.Click += new EventHandler(btnElement_Click);
btnElement.MouseDown += new MouseEventHandler(btnElement_MouseDown);
btnElement.MouseMove += new MouseEventHandler(btnElement_MouseMove);
this.Add(cntButton.ToString(), btnElement);
HostForm.Controls.Add(btnElement);
btnElement.BringToFront();
cntButton++;
}

public void RemoveButton(string btnIndex)
{
if (this.Count > 0)
{
HostForm.Controls.Remove((Button)this[btnIndex]);
this.Remove(btnIndex);
}
}

private void btnElement_Click(Object sender, System.EventArgs e)
{
if(null != SelectedButton)
SelectedButton(sender);
}

private void btnElement_MouseDown(object sender, MouseEventArgs e)
{
buttonLocation = e.Location;
}

private void btnElement_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
((Button)sender).Left += e.X - buttonLocation.X;
((Button)sender).Top += e.Y - buttonLocation.Y;
}
}
}
}
Class “ButtonArray” is inherited from the Hash table, so it will be easy for us to add buttons in the collection. Let’s have a look into the “AddButton” method.


public void AddButton(int left, int top)
{
Button btnElement = new Button();
btnElement.Top = top;
btnElement.Left = left;
btnElement.Tag = cntButton;
btnElement.Cursor = System.Windows.Forms.Cursors.Default;
btnElement.FlatStyle = System.Windows.Forms.FlatStyle.System;
btnElement.Text = "Button " + cntButton.ToString();
btnElement.Click += new EventHandler(btnElement_Click);
btnElement.MouseDown += new MouseEventHandler(btnElement_MouseDown);
btnElement.MouseMove += new MouseEventHandler(btnElement_MouseMove);
this.Add(cntButton.ToString(), btnElement);
HostForm.Controls.Add(btnElement);
btnElement.BringToFront();
cntButton++;
}

In this method, we create an instance of a button with the necessary properties and add it to the hash table as well as to the form’s control collection. Each time the control is added in the hash table with its unique key. This helps us to access the controls when required.
Now we’ll see how to remove control from the hash table and form’s control collection.
In order to remove the control, just pass the key. That’s simple! Isn’t it? :-)


public void RemoveButton(string btnIndex)
{
if (this.Count > 0)
{
HostForm.Controls.Remove((Button)this[btnIndex]);
this.Remove(btnIndex);
}
}


Ok! That was about the methods to add and remove controls from the collection. Now we will see how to use this class from the UI (Form).
First thing to do is to initialise the ButtonArray class and a button.


ButtonArray buttonArray;
Button btnSelected = new Button();

Now create two more buttons on the form and name them as “AddButton” and “RemoveButton”.
Code them as shown below.


private void AddButton_Click(object sender, EventArgs e)
{
isClicked = true;
}
private void RemoveButton_Click(object sender, EventArgs e)
{
buttonArray.RemoveButton(btnSelected.Tag.ToString());
}

Under the Mouse Down event of the form, code as shown below.

private void frmMain_MouseDown(object sender, MouseEventArgs e)
{
if (isClicked)
{
buttonArray.AddButton(e.X, e.Y);
isClicked = false;
}
}


You can add other controls as well. Just create array class for each control type and use it.

And yea, please do not forget to leave a comment on this post.

18 comments:

  1. Hi... thanks alot for this code sample..

    ReplyDelete
  2. Hi..thanks for this..
    but how do we update the properties, meaning if I want change the forecolor of the button...how can i do this..can i achieve in this class itself

    ReplyDelete
  3. Yes you can change the ForeColor by creating a Public method. Something like this.


    public void ForeColor(object sender, Color foreColor)
    {
    ((Button)sender).ForeColor = foreColor;
    }


    Add this method to the ButtonArray.cs class.

    ReplyDelete
  4. Good Post ...

    http://thoughts.agenext.com

    ReplyDelete
  5. This example is conceptually perfect for resolving my problem, save for the fact that I am looking for a VB.Net version. (Yes, this old dog has yet to learn the new tricks of C#.) I will attempt to translate this to VB.Net with the assistance of the excellent commentary you add to the code in this post. Thanks for sharing.

    ReplyDelete
  6. Thank you very much, this code is very useful for dynamic creation of form controls :D

    ReplyDelete
  7. am adding datagridview in the same manner,but wat happen is am unable to add columns for that gridview any help??
    thanks..

    ReplyDelete
  8. You need to get the control by its name.

    DataGridView dtv = HostForm.Controls["dataGridView1.Site.Name"] as DataGridView;

    Now you can access this control and create the columns.

    ReplyDelete
  9. Thanks for your reply..
    Actually am new to this .net application,
    so,can u tell me about this something detailed like where to add this and how can we access this control??

    ReplyDelete
  10. Can we do the same in WPF??
    Thanks in Advance...

    ReplyDelete
  11. HELLO Mazhar Haque is there any way i cant contact you i need your help my email is bloodsville08@hotmail.com
    They thing I wold like to know if its possible is to, at the mouse event of click instead of a new button just click and drag (selecting a rectangular area) and when mouse is release the new button will have the rectangular shape the user decided. if so can you help me there or contact me? thanks a lot for this tutorial

    ReplyDelete
  12. after add a few button, how can i save it by using binary serialization??

    ReplyDelete
  13. You cannot serialize the form or its contents (i.e. child controls) because the controls cannot be serialized. The controls do not have [Serializable] attribute.

    If you want to save the state of your form after adding controls, then create XML and save the properties as nodes within the XML.

    If you are looking for some real form designers and want to save/load controls then i'll suggest you look the below article:

    http://msdn.microsoft.com/en-us/magazine/cc163634.aspx

    ReplyDelete
  14. Hi guys... How about for textboxes... and their name will be increased one by one... like txt.Box01, txtBox02... And to add to a specific place on the form automatically...

    ReplyDelete
  15. Thanks for the tutorial!

    I have a question, if I want to assign an action to the created button, what would be the best way to do so?

    In frmMain.cs I could utilize the buttonArray_SelectedButton function and help myself with an array or a switch/case to decide which action to execute depending on which button was pressed. But there has to be a more elegant way.

    Any suggestions?

    Manu.

    ReplyDelete