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.