o en el caso del TextBox lo hace con la propiedad MultiLine.
Para WindowsForms es necesario tres cosas fundamentales:
1) Diseñar la clase de un control de usuario.
->
System.Windows.Forms.UserControl (pongo como ejemplo esa clase a heredar, por no poner toda la lista de clases de los controles base.)
2) Diseñar la clase que proporciona servicios en tiempo de diseño para el control de usuario al que esté vinculado.
->
System.Windows.Forms.Design.ControlDesigner3) Diseñar la clase que proporciona una lista de acciones o "tareas" para el diseñador de control al que esté vinculado.
->
System.ComponentModel.Design.DesignerActionList
En las url de arriba tienes ejemplos puntuales del uso de cada clase, y aquí tienes más documentación:
-
Designer Commands and the DesignerAction Object Model for Windows Forms. -
Simplify UI Development with Custom Designer Actions in Visual Studio.
Por último, aquí abajo comparto el código fuente de un control de usuario heredado de la clase
RichTextBox al que le he añadido una acción con nombre "
MultiLine" que cumple la misma funcionalidad que la acción "
MultiLine" de un
TextBox. También le añadí la acción con nombre "
Edit Text Lines" donde además demuestro como puedes invocar al editor de lineas mediante el uso de
Reflection (aunque yo en el código original no utilizo
Reflection, solo lo hice así para simplificar el código, pero si lo prefieres puedes invocar el editor de lineas como en este otro ejemplo:
https://stackoverflow.com/a/43826903/1248295 ).
Todo esto ya lo tenía hecho de hace tiempo. El código fuente original de este control de usuario tiene varias miles de lineas. Lo he simplificado al máximo posible recortando todo lo innecesario e irrelevante para resolver tu duda. He recortado la lógica de preservación del texto multilinea al activar y desactivar la acción "MultiLine" ya que era mucho código, aunque por otro lado he dejado intacta la lógica de preservación del tamaño del control al activar y desactivar la acción "MultiLine", ya que eso si que me parece oportuno y relevante y es muy poquito código en comparación.
EnjutoRichTextBox.vb#Region " EnjutoRichTextBox Class "
Namespace Enjuto.UserControls
''' <summary> A extended <see cref="RichTextBox"/> control.</summary>
<DesignTimeVisible(True)>
<Designer(GetType(EnjutoRichTextBoxDesigner))>
<ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Require)>
Public Class EnjutoRichTextBox : Inherits RichTextBox
#Region " Fields "
''' <summary>Fixed control height for single-line mode.</summary>
Protected ReadOnly singleLineFixedControlHeight As Integer
''' <summary>Keeps track of control's height while multi-line is enabled.</summary>
Protected multiLineCurrentControlHeight As Integer
#End Region
#Region " Constructors "
<DebuggerStepThrough>
Public Sub New()
Me.SuspendLayout()
Me.DoubleBuffered = True
Using tb As New TextBox(), rtb As New RichTextBox()
Me.singleLineFixedControlHeight = tb.Size.Height
Me.Size = rtb.Size
End Using
Me.ResumeLayout(performLayout:=False)
End Sub
#End Region
#Region " Event Invocators "
''' <summary>Raises the <see cref="EnjutoRichTextBox.MultilineChanged"/> event.</summary>
Protected Overrides Sub OnMultilineChanged(e As EventArgs)
If Not Me.Multiline Then
Me.multiLineCurrentControlHeight = Me.Height
Me.Height = Me.singleLineFixedControlHeight
Me.SetStyle(ControlStyles.FixedHeight, True)
Else
Me.SetStyle(ControlStyles.FixedHeight, False)
Me.Height = Me.multiLineCurrentControlHeight
End If
MyBase.OnMultilineChanged(e)
End Sub
#End Region
End Class
End Namespace
#End Region
EnjutoRichTextBoxDesigner.vbImports System.ComponentModel.Design
Imports System.Windows.Forms.Design
#Region " EnjutoRichTextBoxDesigner Class"
Namespace Enjuto.UserControls
''' <summary>Provides design-time support for the <see cref="EnjutoRichTextBox"/> control.</summary>
Friend NotInheritable Class EnjutoRichTextBoxDesigner : Inherits ControlDesigner
#Region " Fields "
Private actionListCollection As DesignerActionListCollection
#End Region
#Region " Properties "
''' <summary>Gets the design-time action lists supported by the component associated with the designer.</summary>
Public Overrides ReadOnly Property ActionLists As DesignerActionListCollection
Get
If Me.actionListCollection Is Nothing Then
Me.actionListCollection = New DesignerActionListCollection From {
New EnjutoRichTextBoxActionList(DirectCast(Me.Component, EnjutoRichTextBox))
}
End If
Return Me.actionListCollection
End Get
End Property
''' <summary>Gets the selection rules that indicate the movement capabilities of a component.</summary>
Public Overrides ReadOnly Property SelectionRules As SelectionRules
Get
Dim rtb As EnjutoRichTextBox = DirectCast(MyBase.Control, EnjutoRichTextBox)
If rtb Is Nothing Then
Return MyBase.SelectionRules
Else
Return If(rtb.Multiline,
SelectionRules.AllSizeable Or SelectionRules.Moveable,
SelectionRules.LeftSizeable Or ' Prevents control height resizing at design-time.
SelectionRules.RightSizeable Or ' *
SelectionRules.Moveable) ' *
End If
End Get
End Property
#End Region
End Class
End Namespace
#End Region
EnjutoRichTextBoxActionList.vbImports System.ComponentModel.Design
Imports System.Diagnostics.CodeAnalysis
Imports System.Reflection
Imports System.Windows.Forms.Design
Imports Enjuto.UserControls
#Region " EnjutoRichTextBoxActionList Class"
''' <summary>Provides designer action list support for the <see cref="EnjutoRichTextBox"/> control.</summary>
Friend NotInheritable Class EnjutoRichTextBoxActionList : Inherits DesignerActionList
#Region " Private Fields "
<SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification:="Needed for EnjutoRichTextBoxActionList.New(component As EnjutoRichTextBox)")>
Private ReadOnly designerActionUISvc As DesignerActionUIService
#End Region
#Region " Properties "
Public Shadows ReadOnly Property Component As EnjutoRichTextBox
Get
Return DirectCast(MyBase.Component, EnjutoRichTextBox)
End Get
End Property
''' <summary>Gets or sets a value indicating whether the text of the control can span more than one line.</summary>
Public Property MultiLine As Boolean
Get
Return Me.Component.Multiline
End Get
Set(value As Boolean)
Me.Component.Multiline = value
End Set
End Property
#End Region
#Region " Constructors "
Public Sub New(component As EnjutoRichTextBox)
MyBase.New(component)
' Cache a reference to DesignerActionUIService, so the DesigneractionList can be refreshed.
Me.designerActionUISvc = DirectCast(Me.GetService(GetType(DesignerActionUIService)), DesignerActionUIService)
End Sub
#End Region
#Region " Public Methods "
''' <summary>Returns the collection of <see cref="DesignerActionItem"/> objects contained in the list.</summary>
''' <returns>A <see cref="DesignerActionItem"/> array that contains the items in this list.</returns>
Public Overrides Function GetSortedActionItems() As DesignerActionItemCollection
Dim items As New DesignerActionItemCollection From {
New DesignerActionHeaderItem("Behavior"),
New DesignerActionPropertyItem("MultiLine", "MultiLine", "Behavior",
"Controls whether the text of the control can span more than one line.")
}
If Me.Component.Multiline Then
items.Add(New DesignerActionMethodItem(Me, "EditTextLines", "Edit Text Lines...", "Behavior",
"Display the Lines collection editor.", includeAsDesignerVerb:=False))
End If
Return items
End Function
#End Region
#Region " Private Methods "
''' <summary> Displays a <see cref="MultilineStringEditor"/> to edit the text lines of the control.</summary>
Friend Sub EditTextLines()
Dim rtb As EnjutoRichTextBox = Me.Component
Dim designerHost As IDesignerHost = rtb.Site.GetService(GetType(IDesignerHost))
Dim designer As IDesigner = designerHost.GetDesigner(rtb)
Dim editorServiceContext As Type = GetType(ControlDesigner).Assembly.DefinedTypes.Where(Function(t As Type) t.Name = "EditorServiceContext").Single()
Dim editValue As MethodInfo = editorServiceContext.GetMethod("EditValue", BindingFlags.Static Or BindingFlags.Public)
editValue.Invoke(Nothing, {designer, rtb, NameOf(rtb.Lines)})
End Sub
#End Region
End Class
#End Region
-Enjuto Mojamuto "rey de los frikis" a su disposición para futuras dudas.