Condividi tramite


Creating an editable control on Custom Designers

A very interesting problem was proposed to me by Microsoft Partner, Dmitry Grigansky. The goal was to create a host designer and have an editable label control placed on it, having this article as a starting base:

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

With help from Dmitry, who relentlessly investigated the matter, here are the main steps for creating this project.

First of all, we create a VS 2010 Win forms project and make sure we set the project for .NET 4 , not .NET 4 Client profile.

Add a reference to System.Design and then create a form named ParentForm. This will be the form on which our Designer will be place.

Next, we create a form named DesignForm, which will be the actual area for the controls to be placed.

On the ParentForm we add this code:

 public ParentForm()
 { 
 InitializeComponent(); 
 System.ComponentModel.Design.DesignSurface
 ds = new System.ComponentModel.Design.DesignSurface(); 
 ds.BeginLoad(typeof(DesignForm));
 Control c = ds.View as Control; 
 c.Parent = this; 
 c.Dock = DockStyle.Fill;
 }

 

Now, the DesignForm is a child of ParentForm.

We will now proceed to the creation of class EditableLabelDesigner derived from ControlDesigner

 

 class EditableLabelDesigner : ControlDesigner 
 { 
 private const int WM_LBUTTONDBLCLK = 0x0203;
 
 public override void Initialize(IComponent
 component) 
 { 
 base.Initialize(component); 
 }
  

     

  protected override void WndProc(ref
 System.Windows.Forms.Message m)
 {
 if (m.Msg == WM_LBUTTONDBLCLK)
 { 
 ((EditableLabel)Control).ShowInplaceEditor();
 }
 base.WndProc(ref m);
 }
 }

 

The WndProc method will catch the WM_LBUTTONDBLCLK event and show the editable area on the label.

 

Next, create the custom control EditableLabel:

Add new user control EditableLabel

 

 [Designer(typeof(EditableLabelDesigner))] 
 
 public partial class EditableLabel : Label
 {
 public EditableLabel()
 { 
 InitializeComponent();
 } 
 
 private TextBox inplaceEditor;
 private bool isRedrawn = false;
 public TextBox InplaceEditor
 {
 get { return inplaceEditor; }
 }
 
 public bool IsRedrawn
 {
 get { return isRedrawn; }
 set
 {
 if (value == true) 
 {
 if (inplaceEditor != null) 
 {
 Text = inplaceEditor.Text;
 inplaceEditor.Visible = false;
 }
 } 
 isRedrawn = value;
 }
 }
 
 
 
 protected override void OnPaint(PaintEventArgs e)
 {
 if (!isRedrawn)
 { 
 IsRedrawn = true;
 }
 base.OnPaint(e);
 }
 
 public void ShowInplaceEditor()
 { 
 isRedrawn = false;
 if (inplaceEditor == null)
 { 
 this.inplaceEditor = new TextBox(); 
 inplaceEditor.Parent = this.Parent.Parent; 
 inplaceEditor.Multiline = true;
 }
 
 
 inplaceEditor.HideSelection = false; 
 inplaceEditor.AcceptsTab = true; 
 inplaceEditor.Text = this.Text; 
 inplaceEditor.Visible = true; 
 inplaceEditor.Location = new Point(this.Parent.Location.X
 + this.Location.X + 10, this.Parent.Location.Y + this.Location.Y
 + 32); 
 inplaceEditor.Size = new Size(this.ClientRectangle.Width
 - 4, this.ClientRectangle.Height - 4); 
 inplaceEditor.Font = this.Font; 
 inplaceEditor.SelectAll(); 
 inplaceEditor.BringToFront(); 
 inplaceEditor.Focus();
 }
 }
 

In the ShowInplaceEditor, the TextBox is added to the DesignForm’s parent, so it will be editable. 

Finally, in the ParentForm constructor, we add the EditableLabel on the DesignFom:

  IDesignerHost idh = (IDesignerHost)ds.GetService(typeof(IDesignerHost));
 IToolboxUser itu = (IToolboxUser)idh.GetDesigner(idh.RootComponent); 
 itu.ToolPicked(new ToolboxItem(typeof(EditableLabel)));

 

Make sure to put the ParentForm as the staring form of your project, and you’re done.

You can find the sample project here.