Have a UserControl with a Label, a homebrew "TextBox" (inherited directly from Control) and a Button. The goal is to have the label "glued" to the relevant controls, so the design of forms is more straightforward. I overrided the OnPaint() event, so the witdh of the "TextBox" is computed taking into account the width of the label. Which in turn have its text taken from a designable property of the UserControl. This way, the full width of the UserControl is what is seen in the designer. All computing is correctly done (when the text for the label is bigger, the text width is lesser, and viceversa... ). More again: if the label text is empty, the label is marked as no visible, and the like. But the label is not shown. Some ideas? TIA
2 Answers
I followed Shell's advice. But with a twist. If you try to DrawString() from the UserControl OnPaint event, nohing happens, because the OnPaint for the form is triggered after all control's, so it wipes out the text. What I resorted to was to create a method in the Form in wich the UserControl is contained and set it as an interface. Some code follows
The interface and auxiliary class
public interface IKindForm
{
void DisplayText( DisplayText t );
}
public class DisplayText
{
public string Text { get; protected set; }
public Font Font { get; protected set; }
public Brush Brush { get; protected set; }
public Point Point { get; protected set; }
public DisplayText( string text, Font font, Color color, int x, int y )
{
Text = text;
Font = font;
Brush = new SolidBrush( color );
Point = new Point( x, y );
}
}
The method in the form which implements the interface and the overrided OnPaint
private List<DisplayText> textsToDisplay = new List<DisplayText>();
public void DisplayText( DisplayText t )
{
if (textsToDisplay.Contains( t ))
return;
textsToDisplay.Add( t );
Invalidate();
}
protected override void OnPaint( PaintEventArgs e )
{
foreach (DisplayText t in textsToDisplay)
e.Graphics.DrawString( t.Text, t.Font, t.Brush, t.Point );
base.OnPaint( e );
}
And finally, the code in the UserControl
bool labelRegistered = false;
protected override void OnPaint( PaintEventArgs e )
{
int textStart = 0;
SizeF ssize = new SizeF( 0, 0 );
if (labelText != null && labelText != String.Empty) {
ssize = e.Graphics.MeasureString( labelText, labelFont );
textStart = (int)ssize.Width;
}
if (ssize.Width > 0) {
if (this.TopLevelControl is IKindForm) {
if (!labelRegistered) {
int yPos = this.Location.Y + margin + ComboText.Size.Height / 4;
int xPos = this.Location.X - ( textStart + labelOffset );
((IKindForm)this.TopLevelControl).DisplayText( new DisplayText( labelText, LabelFont, labelColor,
xPos, yPos ) );
}
}
labelRegistered = true;
}
Only drawback is that when in designer, the TopLevelControl is not a IKindForm one, so you cannot see the "label".
You cannot add the label in user control inherited by textbox. you have to place both control(label and textbox) separately on user control instead of inheriting. thus, you can set the textbox's size and location programatically. and you have to create all properties which you want to handle outside the class or namespace.
for example
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Browsable(true)]
[DefaultValue(string.Empty)]
public override string Text
{
get {
return txtBox.Text;
}
set {
txtBox.Text = value;
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Browsable(true)]
[DefaultValue("My Lable:")]
public string LabelText
{
get{
return lblLabel.Text;
}
Set {
lblLabel.Text = value;
}
}