okkko
okkko

Reputation: 1070

Default inherited button text

This is the code for my inherited Button control:

Public Class ButtonRefreshSmall
Inherits Button

Public Sub New()
    MyBase.New
    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    Me.SuspendLayout()
    Me.Text = ""
    MyBase.Text = ""
    Me.ResumeLayout()
End Sub
End Class

However, when I rebuild and drag this button to a form the text is always ButtonRefreshSmall1. I've tried variants without the Inherits declaration (since it's already in the .Designer.vb file, I've tried setting Text in Designer view/class of the control, to no avail.
Sometimes it won't even show in the Toolbox after rebuild.

All I want is for text of the button to be empty (since it has an Image defined in the designer).

This is what I have in the Designer file:

 <System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
    Me.SuspendLayout()
    '
    'ButtonRefreshSmall
    '
    Me.BackColor = System.Drawing.Color.Transparent
    Me.FlatAppearance.BorderSize = 0
    Me.FlatStyle = System.Windows.Forms.FlatStyle.Flat
    Me.Image = Global.TraxCashFlow.My.Resources.Resources.Refresh_grey_16x
    Me.Size = New System.Drawing.Size(23, 23)
    Me.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText
    Me.UseVisualStyleBackColor = False
    'MyBase.Text = ""
    Me.ResumeLayout(False)

End Sub

And all other properties are set like I set them. I tried to trick it with TextImageRelation but the "B" is always visible anyway.

Update: Jimi gave me the idea in a comment below his answer, so I added a new Property MyText and this works just like I want (not sure why I need to call Refresh though, if I don't then it's updated after losing focus):

Imports System.ComponentModel

Public Class ButtonRefreshSmall

Public Property MyText As String
    Get
        Return Me.Text
    End Get
    Set(value As String)
        Me.Text = value
        Me.Refresh()
    End Set
End Property

Public Sub New()
    'MyBase.New
    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    'Me.Text = ""
End Sub

<Browsable(False)>
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Public Overrides Property Text As String
End Class

Update #2, see @TnTinMn's answer.

Upvotes: 3

Views: 830

Answers (3)

TnTinMn
TnTinMn

Reputation: 11801

To accomplish the goal you stated in a comment to the accepted answer,

... I'd want Text property to remain but just to be empty ...

You can apply a ToolboxItemAttribute to your custom button class.

<System.ComponentModel.ToolboxItemAttribute(GetType(ToolBoxItemNoDefaultText))>
Public Class ButtonRefreshSmall

This will tell the design environment to use the class ToolBoxItemNoDefaultText to control the creation of ButtonRefreshSmall for placement on the design surface. ToolBoxItemNoDefaultText will derive from the ToolboxItem Class.

Imports System.Drawing.Design
Imports System.ComponentModel
Imports System.Runtime.Serialization
Imports System.Windows.Forms

<Serializable()> ' ToolBoxItems must be Serializable 
Public Class ToolBoxItemNoDefaultText : Inherits ToolboxItem
  Public Sub New(ByVal toolType As Type)
    ' this constructor is needed to allow the type decorated with 
    ' <System.ComponentModel.ToolboxItemAttribute(GetType(ToolBoxItemNoDefaultText))>
    ' to be added to the ToolBox
    MyBase.New(toolType)
  End Sub

  Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
    ' this constructor is needed to support the design-time deserialization of this
    ' class by the design environment.
    Deserialize(info, context)
  End Sub

  Protected Overrides Sub OnComponentsCreated(args As ToolboxComponentsCreatedEventArgs)
    ' this will run after all initialization code has run including that set
    ' by the component's designer, thus you can override designer set values.
    For Each comp As IComponent In args.Components
      Dim ctrl As Control = TryCast(comp, Control)
      If ctrl IsNot Nothing Then ctrl.Text = String.Empty
    Next
    MyBase.OnComponentsCreated(args)
  End Sub
End Class

This solution is somewhat after the fact as it allows the default designer code to run and then modifies the created instance. You may notice that the Text set by the designer is momentarily displayed before it is set to String.Empty.

The proper way to deal with this would be to create a custom designer and not set the Text property during initialization. However, proper implementation of a custom designer can become involved if the user experience is to be as close as possible that implemented by MS.

Upvotes: 3

Jimi
Jimi

Reputation: 32223

Simple way: override or shadow the Text property, adding a DesignerSerializationVisibility Attribute, setting it to DesignerSerializationVisibility.Hidden and the Browsable attribute to False.

The Designer won't generate any code for the Text property (so the Control won't show a text), the property is not visible in the PropertyGrid but it's still there and can be set in code.

<Browsable(False)>
<DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)>
Public Overrides Property Text As String
' or
' Public Shadows Property Text As String

Another way is to remove the property, using a custom designer.
See here how it can be implemented:
Is it possible to change the value of a property attribute at design time?

Upvotes: 2

jmcilhinney
jmcilhinney

Reputation: 54417

That's just what the WinForms designer does. When you add a control to the form, it sets the Name and Text properties based on the type of the control and the number of them that are on the form with default names. It's done after the constructor is executed so your constructor code can't help. You'd have to put code in the property itself to ignore a set in the designer:

Public Overrides Property Text As String
    Get
        Return MyBase.Text
    End Get
    Set
        If Not DesignMode Then
            MyBase.Text = Value
        End If
    End Set
End Property

Note that that means that you won't be able to set it yourself either though, unless at run-time.

Upvotes: 2

Related Questions