Lech Krawczyk
Lech Krawczyk

Reputation: 21

Generate custom C# code in Form.cs while dropping user control in Form1.cs at design time

I have a user control that I can drag and drop in the Form1.cs[Design] mode. The designer will auto-generate code for this user control in the Form1.Designer.cs

What I would like to get aswell is: at the moment I am adding the user control to the form by dragging I wont to have code generated in my Form.cs that is pointing to the properties and controls on that user control.

Example of user control:

public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    public string TextInTextBox
    {
        get { return textBox1.Text; }
        set { textBox1.Text = value; }
    }
}

So now when I drag it on the form in the Form1.cs[Design]. I won't part of code like this to be generated in my Form1.cs:

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

    // this code below to be auto-generated
    private void AddText()
    {
        userControl11.TextInTextBox = "";
    }
}

I think I should be looking for something like inheritance or interface but I would like this to happen for each instance of that user control. If someone could point me direction what to look for it would be great. Thanks.

Upvotes: 0

Views: 299

Answers (1)

Reza Aghaei
Reza Aghaei

Reputation: 125277

Usually you don't need to generate code manually when you want to assign a property when dropping a control from toolbox, for example you can easily do this:

public MyUserControl()
{
    InitializeComponent();
    MyTextProperty = "Something";
}

And it will be serialized automatically.

But there are more options for more advanced requirements.if you know the options that you have, you may choose based on your requirement. Here is some options:

  • Assign some value in constructor or to the property
  • Assign value to properties using ToolboxItem, it will overwrite the value which you assign in constructor.
  • Generate some code for Load event of form and initialize property there. It's useful for complex code generations, for example when you drop a data source it will generate some code to load data and add to load event of form.

Assuming you have assigned Something to MyTextProperty in constructor, then when you drop the control in form, here is what will be generated in designer.cs:

this.myUserControl1.MyTextProperty = "Something";

If you use the ToolboxItem solution to assign Something else to the property, the result in designer.cs file will be:

this.myUserControl1.MyTextProperty = "Something else";

And if you decide to use third option and generate event handler code, the result in designer.cs file will be:

this.Load += new System.EventHandler(this.Form1_Load);

and the result in cs file will be:

private void Form1_Load(object sender, EventArgs e)
{
    myUserControl1.MyTextProperty = "Even something else!";
}

Example

Here is a full code of MyUserControl, MyUserControlToolboxItem and MyUserControlDesigner. You can comment Designer and/or ToolboxItem attributes and close all designers and clean and rebuild the solution and drop an instance of the control on the form to see how it works.

using System.CodeDom;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;

[Designer(typeof(MyUserControlDesigner))]
[ToolboxItem(typeof(MyUserControlToolBoxItem))]
public partial class MyUserControl : UserControl
{
    public MyUserControl()
    {
        InitializeComponent();
    }
    public string MyTextProperty { get; set; } = "Something";
}

public class MyUserControlToolBoxItem : ToolboxItem
{
    protected override IComponent[] CreateComponentsCore(IDesignerHost host)
    {
        IComponent[] componentsCore = base.CreateComponentsCore(host);
        if (componentsCore != null && componentsCore.Length > 0
            && componentsCore[0] is MyUserControl)
            (componentsCore[0] as MyUserControl)
                .MyTextProperty = "Something else"; ;
        return componentsCore;
    }
}

public class MyUserControlDesigner : ControlDesigner
{
    public override void InitializeNewComponent(IDictionary defaultValues)
    {
        base.InitializeNewComponent(defaultValues);
        var component = Control;
        var eventBindingService = (IEventBindingService)this.GetService(
            typeof(IEventBindingService));
        var componentChangeService = (IComponentChangeService)this.GetService(
            typeof(IComponentChangeService));
        var designerHostService = (IDesignerHost)GetService(typeof(IDesignerHost));
        var rootComponent = designerHostService.RootComponent;
        var uiService = (IUIService)GetService(typeof(IUIService));
        var designerTransaction = (DesignerTransaction)null;
        try
        {
            designerTransaction = designerHostService.CreateTransaction();
            var e = TypeDescriptor.GetEvents(rootComponent)["Load"];
            if (e != null)
            {
                var methodName = "";
                var eventProperty = eventBindingService.GetEventProperty(e);
                if (eventProperty.GetValue(rootComponent) == null)
                {
                    methodName = eventBindingService
                        .CreateUniqueMethodName(rootComponent, e);
                    eventProperty.SetValue(rootComponent, methodName);
                }
                else
                    methodName = (string)eventProperty.GetValue(rootComponent);
                var code = this.GetService(typeof(CodeTypeDeclaration))
                        as CodeTypeDeclaration;
                CodeMemberMethod method = null;
                var member = code.Members.Cast<CodeTypeMember>()
                    .Where(x => x.Name == methodName).FirstOrDefault();
                if (member != null)
                {
                    method = (CodeMemberMethod)member;
                    method.Statements.Add(
                        new CodeSnippetStatement($"{Control.Name}" +
                        $".MyTextProperty = \"Even something else!\";"));
                }
                componentChangeService.OnComponentChanged(rootComponent,
                    eventProperty, null, null);
                eventBindingService.ShowCode(rootComponent, e);
            }
            designerTransaction.Commit();
        }
        catch (System.Exception ex)
        {
            if (designerTransaction != null)
                designerTransaction.Cancel();
            uiService.ShowError(ex);
        }
    }
}

Upvotes: 1

Related Questions