Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Absolute Dynamic Form at Runtime

0.00/5 (No votes)
17 Jun 2014 1  
How to add and code dynamic .NET controls during runtime

Sample Image - maximum width is 600 pixels

Introduction

This article is going to explain how you can create a control during runtime, move the control in your form and finally how to add functionality to your control.

To do this task, this project comes in three parts:

  • Add and move controls dynamically
  • Code controls dynamically
  • and finally serialize a form with all controls and all code to the harddrive

If you want to skip the whole reading part and start exploring, click on download demo project.
If you want to use the code yourself, just add a reference to all DLLs in the redist folder.

The code below shows how to do all 3 tasks:

using DynamicV2; 
using Dyncontrols; 

var Button=Extensions.Control_Create(typeof(Button), new Point(100, 100));

Extensions.Control_MoveandResize(Button);
        
new Codeeditor(Button).Show();

byte[] control=ControlFactory.Serialize(Button);

Background

Sometimes, we see that we want to make changes in the behaviour of our form. We need to add buttons and add events, but can we do all that during runtime?
Yes we can!

Some time ago, a little thing came out. It was called CodeDom Provider Class. It enables us to compile classes dynamically from scratch during runtime.
This basically means that we can create class instances out of thin air which we can use to subscribe and unsubscribe events and code for dynamic buttons.

To make things more convenient for you, I have used several assemblies written by other people for this project. I do not claim to have created any of them:

In my opinion by far the best C# editor control. Check it out:

Foundation for simple moving controls. I have added a snap to other control logic.

Foundation for the serialization of forms and controls. I made this recursive to handle controls with controls. (scrollbar, etc.)

Creating a Movable Control

Extensions.Control_MoveandResize(Button);

This also enables automatic layout positioning. Very handy.

Using the Compiler

The following lines are automatically created for you. You can enter new code in the editor window. All variables are casted into the right type. A doubleclick onto the event treeview adds the code for the eventhandler and enables easy code input. All variable names can be changed when the code window is closed. Meaning you can name all your buttons and checkboxes as you wish.
Below you see what actually happens:

Sample Image - maximum width is 600 pixels

#region Declarations
private System.Windows.Forms.CheckBox CheckBox0; 
private System.Windows.Forms.GroupBox GroupBox0; 
private System.Windows.Forms.Button Pressbutton; 
private System.Windows.Forms.Form Mainwindow; 
//All initializations: 
    public void ControlInit(object Controlobj,List<control> Customercollection ) 
{ 
    CheckBox0 = (System.Windows.Forms.CheckBox)Customercollection[0]; 
    GroupBox0 = (System.Windows.Forms.GroupBox)Customercollection[1]; 
    Pressbutton = (System.Windows.Forms.Button)Customercollection[2]; 
    Mainwindow = (System.Windows.Forms.Form)Customercollection[3]; 
    Pressbutton.Click+= new EventHandler(Pressbutton_Click); 
} 
#endregion Declarations

On the "other side" (not changeable part of the form) is this code: It compiles the string and adds a reference to all controls into an object array passed to the changeclass which is created by codedom.

provider.CompileAssemblyFromSource(Parameters, syntaxEdit1.Text););
var o = results.CompiledAssembly.CreateInstance("Dynamicform.Changeclass"); 
MethodInfo setevents = o.GetType().GetMethod("ControlInit"); 
object[] arr = new object[2]; 
arr[0] = Patient; 
arr[1] = Extensions.GetSelfAndChildrenRecursive(Patient.FindForm()).ToList(); 
try 
{ 
    setevents.Invoke();
}

If your code throws an exception, during execution there is a cryptic error message like: Unhandled exception in c826asdk.dll which won't help you.
So all exceptions are caught and the first two elements of the stack are displayed. --> Error in Button0_clickton0_click.

Serializing a Form

Please check out:

Basically, all you have to do to serialize a control is to serialize all properties which are marked as serializable and store the parent and child references.
I have expanded the class to support serialisation to file or to byte[] of a form or a control. If you wish to load a form from file, just write:

ControlFactory.Serializetofile(this, "Visuals.inf");

var form = ControlFactory.Deserializefromfile("Visuals.inf") as Form; 
Application.Run(form);    

Doesn't get any easier than that.

public static void Serializetofile(Control Serialize,string filename) 
{ 
var controls = GetSelfAndChildrenRecursive(Serialize); 
List<Tuple<CBFormCtrl, string,string>> 
dictionary=new List<System.Tuple<CBFormCtrl,string,string>>();
 
foreach (Control k in controls) 
{ 
    if (k.Parent != null) 
    { 
        dictionary.Add(new Tuple<CBFormCtrl, string,string>
        (new CBFormCtrl(k), k.GetHashCode().ToString(),k.Parent.GetHashCode().ToString())); 
    } 
    else 
    { 
        //parent
        dictionary.Add(new Tuple<CBFormCtrl, string, 
        string>(new CBFormCtrl(k), k.GetHashCode().ToString(), "null")); } 
    } 

    var file = File.Create(filename); 
    BinaryFormatter formatter = new BinaryFormatter(); 
    formatter.Serialize(file, dictionary); 
    file.Close(); 
} 

Points of interest

During the coding, I wanted to have icons for each control. I found out that there is a way to extract the toolbox image from any control!

var k=new BIcon.FromHandle(new Bitmap
(new System.Drawing.ToolboxBitmapAttribute(k.GetType()).GetImage(k)).GetHicon());

Conclusion

You can use this project to create working Windows Forms and import them in other applications. You can use parts of it for control serialization or control relocation. You can change all properties during runtime.

Limitations

Creating buttons moving them and making code for them during runtime is fun but it comes at a cost:

  • Each time you edit your code, a new assembly is created and loaded into the appdomain. DLLs can not be unloaded from one appdomain.
  • Not all properties are serializable. The buttons may look the same but they do not share most of the properties. All other links to controls but parent and children are lost.
  • Debugging gets hard if you are working in a deserialized class instance.
  • The codeditor uses the tag property of any control as storage space for the source code.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here