【问题标题】:Default inherited button text默认继承按钮文本
【发布时间】:2019-06-17 13:25:42
【问题描述】:

这是我继承的 Button 控件的代码:

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

但是,当我重建此按钮并将其拖动到表单时,文本始终为ButtonRefreshSmall1。我尝试了没有Inherits 声明的变体(因为它已经在.Designer.vb 文件中,我尝试在控件的设计器视图/类中设置Text,但无济于事。
有时重建后它甚至不会显示在工具箱中。

我只想让按钮的文本为空(因为它在设计器中定义了Image)。

这是我在 Designer 文件中的内容:

 <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

所有其他属性都像我设置的那样设置。我试图用TextImageRelation 欺骗它,但无论如何“B”总是可见的。

更新:Jimi 在他的答案下方的评论中给了我这个想法,所以我添加了一个新的PropertyMyText,这就像我想要的那样工作(不知道为什么我需要打电话给Refresh,如果我不要在失去焦点后更新):

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

更新 #2,请参阅@TnTinMn 的回答。

【问题讨论】:

标签: vb.net winforms custom-controls windows-forms-designer


【解决方案1】:

为了实现您在对已接受答案的评论中陈述的目标,

...我希望 Text 属性保留但只是为空...

您可以将ToolboxItemAttribute 应用于您的自定义按钮类。

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

这将告诉设计环境使用类ToolBoxItemNoDefaultText 来控制ButtonRefreshSmall 的创建以放置在设计图面上。 ToolBoxItemNoDefaultText 将派生自 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

这个解决方案有点事后,因为它允许默认设计器代码运行,然后修改创建的实例。您可能会注意到设计者设置的Text 在设置为String.Empty 之前会暂时显示。

处理这个问题的正确方法是创建一个自定义设计器,而不是在初始化期间设置Text 属性。但是,如果要尽可能接近 MS 实现的用户体验,则可能会涉及到自定义设计器的正确实现。

【讨论】:

  • 查看我的问题中的更新,我认为它更简单。
  • @okkko,您可能会发现它更简单地满足您的需求,但如果您再次需要这种行为。您需要复制您设计的整个代码模式,而不是添加一行额外代码来添加 ToolboxItemAttribute。
  • 你是对的! Tbh,我以前没有真正看过你的代码,但现在我已经尝试过了,它工作得很好,没有瞬间 Tex 注意到。赞成并接受作为答案,对不起吉米!我想它们是简单问题的许多解决方案。
【解决方案2】:

这正是 WinForms 设计器所做的。当您将控件添加到窗体时,它会根据控件的类型以及窗体上具有默认名称的控件的数量来设置 Name 和 Text 属性。它是在构造函数执行后完成的,所以你的构造函数代码无济于事。您必须在属性本身中添加代码才能忽略设计器中的集合:

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

请注意,这意味着您也无法自行设置,除非在运行时。

【讨论】:

    【解决方案3】:

    简单方法:覆盖或隐藏Text属性,添加DesignerSerializationVisibility属性,将其设置为DesignerSerializationVisibility.Hidden,将Browsable属性设置为False。

    设计器不会为 Text 属性生成任何代码(因此控件不会显示文本),该属性在 PropertyGrid 中不可见,但它仍然存在并且可以在代码中设置。

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

    另一种方法是使用自定义设计器删除该属性。
    看看这里是如何实现的:
    Is it possible to change the value of a property attribute at design time?

    【讨论】:

    • 两个答案都很好,同时也是一种妥协。我希望 Text 属性保持不变,但只是为空。对于这种特殊情况,我接受这是一个答案。
    • 正如我在回答中所说,无论如何您都无法在设计器中自己设置Text,因此将其隐藏在设计器中是一个更好的选择。您仍然可以在代码中设置它,因为正如这个答案所说,该属性仍然存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多