0

Problem

I was trying to create a custom control which contains nothing but a label. However, I wanted the label's text to be changed to what the name property of the custom control has received at design time.

This is what my custom control's class looks like:

public partial class Tile : UserControl
{

     public Tile()
     {
         InitializeComponent();
     }

     [Browsable(true)]
     public override string Text { get => label1.Text; set => label1.Text = value; }
}

As you can see, I've overridden the UserControl's Text property in a way that it updates the Label's text too as soon as the Name is updated which in the end did not work. What happened was when I dragged the control from Toolbox to form the label got updated as expected but the moment I build the project, the designer got refreshed and the Label's text was lost.


What I tried

  • DesignerSerializationAttribute

    Going through Google I came upon a solution given at StackOverflow itself by Hans Passant that using DesignerSerializationAttribute(DesignerSerializationVisibility.Visible) can solve the problem as the value the Text property is given will be persisted in the initialization code which seems valid when it was getting lost at first (value didn't persisted and lost upon designer repaint).

    So I changed my property like this:

    [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public override string Text { get => label1.Text; set => label1.Text = value; }
    

Doing such change actually solved the issue and now it was working even If I build the project.


What I found

Though my issue got solved but then I started to look for another way to approach the same result.

While experimenting more with my code I found that If I create another property that exposes the label's Text property and update it using the overridden Text property it works exactly what it was working using DesignerSerializationAttribute.

Here what the new code looks like:

   [Browsable(false)]
   public string LabelText { get => label1.Text; set => label1.Text = value; }

   [Browsable(true)]
   public override string Text { get => LabelText; set => LabelText = value; }

I wanted to know that

Why this works (even without DesignerSerializationVisibility):

Text---->LabelText---->Label's Text

I might be asking something very obvious right now but I've been reading about it since hours which made it a bit confusing for me .

  • 1
    That's because `Text` property of user control is marked as hidden (not serialized). In the second scenario, your new property is serialized and is keeping the text for future use. – Reza Aghaei Jan 24 '22 at 17:48
  • 1
    Default behavior for a property is to get serialized, but explicitly [turned off](https://stackoverflow.com/a/2881855/17034) for the UserControl.Text property. So LabelText gets serialized, [Browsable(false)] doesn't stop that, in effect preserving the Text property. Sensible thing to do is just turn these attributes back on, also Bindable and EditorBrowsable. – Hans Passant Jan 24 '22 at 18:00
  • @HansPassant I used `[Browsable(false)]` otherwise It would display two properties(basically duplicate) which do not make sense. – Abhinav Pandey Jan 25 '22 at 04:04

1 Answers1

1

If you look at the source code of UserControl, you can see the Text property is marked as not serializable by designer, so basically the value of the property will be lost after you close the form:

[Browsable(false),
EditorBrowsable(EditorBrowsableState.Never), 
Bindable(false), 
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get {
        return base.Text;
    }
    set {
        base.Text = value;
    }
}

But in your alternative solution, designer will serialize LabelText property, and later will use its value to return as Text. That's why it works.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398