如何将 RichTextBox 行尾从 Lf 更改为 CrLf [英] How to change RichTextBox line endings from Lf to CrLf
问题描述
相对于 TextBox 控件其中使用 CrLf
行结束 RichTextBox 控件使用 Lf
行结尾.我不想要那个.我需要一致性.我需要一个使用 CrLf 行尾的 RichTextBox 控件.
As opposed to the TextBox control which use CrLf
line endings the RichTextBox control use Lf
line endings. I don't want that. I need consistency. I need a RichTextBox control whom use CrLf line endings.
我在reflector中打开控件,注意到Text
属性的getter调用了以下函数:
I opened the control in reflector and noticed that the getter of the Text
property calls the following function:
Private Function StreamOut(ByVal flags As Integer) As String
'...
Me.StreamOut(data, flags, False)
'...
End Function
最终调用:
Private Sub StreamOut(ByVal data As Stream, ByVal flags As Integer, ByVal includeCrLfs As Boolean)
'...
Dim es As New EDITSTREAM
'...
ElseIf includeCrLfs Then
num = (num Or &H20)
Else
'...
es.dwCookie = DirectCast(num, IntPtr)
'...
End Sub
如您所见,includeCrLfs
参数将始终为 False
.
And as you can see, the includeCrLfs
parameter will always be False
.
于是我将控件子类化并截获了EM_STREAMOUT 消息.此消息的 LParam
包含指向 EDITSTREAM 结构.我在上面的函数中添加了 &H20
标志,但这不起作用.Text
属性开始返回空字符串.我相信我可能需要删除/附加其他标志,但我不知道哪些标志.此外,除了应用程序定义的值之外,MSDN 不提供任何提示.
So I subclassed the control and intercepted the EM_STREAMOUT message. The LParam
of this message contains the pointer to the EDITSTREAM structure. I appended the &H20
flag as seen in the function above, but this didn't work. The Text
property started to return an empty string. I believe that I might have to remove/append other flags, but I have no clue as to which flags. Also, MSDN do not provide any hints other than application-defined value.
dwCookie
指定一个应用程序定义的值,富编辑控件传递给 pfnCallback 成员指定的 EditStreamCallback 回调函数.
这是我的子类控件:
Public Class UIRichTextBox
Inherits System.Windows.Forms.RichTextBox
Private Sub EmStreamOut(ByRef m As Message)
Dim es As New EDITSTREAM
es = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(EDITSTREAM)), EDITSTREAM)
If (IntPtr.Size = 4) Then
Dim cookie As Int32 = es.dwCookie.ToInt32()
'cookie = (cookie Or &H20I) '<- Didn't work
es.dwCookie = New IntPtr(cookie)
Else
Dim cookie As Int64 = es.dwCookie.ToInt64()
'cookie = (cookie Or &H20L) '<- Didn't work
es.dwCookie = New IntPtr(cookie)
End If
Marshal.StructureToPtr(es, m.LParam, True)
MyBase.WndProc(m)
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case m.Msg
Case EM_STREAMOUT
Me.EmStreamOut(m)
Exit Select
Case Else
MyBase.WndProc(m)
Exit Select
End Select
End Sub
Private Const EM_STREAMOUT As Integer = &H44A
Private Delegate Function EDITSTREAMCALLBACK(ByVal dwCookie As IntPtr, ByVal buf As IntPtr, ByVal cb As Integer, <Out()> ByRef transferred As Integer) As Integer
<StructLayout(LayoutKind.Sequential)> _
Private Class EDITSTREAM
Public dwCookie As IntPtr = IntPtr.Zero
Public dwError As Integer
Public pfnCallback As EDITSTREAMCALLBACK
End Class
End Class
更新
所以事实证明这些标志根本就没有记录.它们是EM_GETEDITSTYLE<的一部分/a> 和 EM_SETEDITSTYLE> 消息.但正如您所见,该标志已过时.
So it turns out that the flags are not undocumented at all. They are part of the EM_GETEDITSTYLE and EM_SETEDITSTYLE messages. But as you can see, the flag is obsolete.
SES_USECRLF 已过时.不要使用.
所以我想我又回到了覆盖 text 属性的第一个方面.
So I guess I'm back at square one overriding the text property.
Public Overrides Property Text() As String
Get
Dim value As String = MyBase.Text
If (Not value Is Nothing) Then
value = value.Replace(ChrW(13), "")
value = value.Replace(ChrW(10), Environment.NewLine)
End If
Return value
End Get
Set(value As String)
MyBase.Text = value
End Set
End Property
推荐答案
所以我设法使用反射创建了一个可行的解决方案.我敢肯定 SES_USECRLF
已过时的原因一定有充分的理由,因此请谨慎操作.
So I managed to create a working solution using reflection. I'm sure there must be a good reason as to why SES_USECRLF
is obsolete, so proceed with caution.
Public Class UIRichTextBox
Inherits System.Windows.Forms.RichTextBox
Shared Sub New()
UIRichTextBox.InternalEditStream = GetType(System.Windows.Forms.RichTextBox).GetField("editStream", (BindingFlags.NonPublic Or BindingFlags.Instance))
UIRichTextBox.InternalStreamIn = GetType(System.Windows.Forms.RichTextBox).GetMethod("StreamIn", (BindingFlags.NonPublic Or BindingFlags.Instance), Nothing, New Type() {GetType(System.IO.Stream), GetType(System.Int32)}, Nothing)
UIRichTextBox.InternalStreamOut = GetType(System.Windows.Forms.RichTextBox).GetMethod("StreamOut", (BindingFlags.NonPublic Or BindingFlags.Instance), Nothing, New Type() {GetType(System.IO.Stream), GetType(System.Int32), GetType(System.Boolean)}, Nothing)
End Sub
Public Sub New()
Me.m_includeCrLfs = True
End Sub
<DefaultValue(True), Category("Behavior")> _
Public Property IncludeCrLfs() As Boolean
Get
Return Me.m_includeCrLfs
End Get
Set(value As Boolean)
If (value <> Me.m_includeCrLfs) Then
Me.m_includeCrLfs = value
Me.RecreateHandle()
End If
End Set
End Property
Public Overrides Property [Text]() As String
Get
Dim value As String = Nothing
If (Me.StreamOut(&H11, value)) Then
Return value
End If
Return MyBase.[Text]
End Get
Set(ByVal value As String)
If (Not Me.StreamIn(value, &H11)) Then
MyBase.[Text] = value
End If
End Set
End Property
Private Function StreamIn(ByVal str As String, ByVal flags As Integer) As Boolean
If (((Me.IsHandleCreated AndAlso ((Not Me.IsDisposed) AndAlso (Not Me.Disposing))) AndAlso ((Not str Is Nothing) AndAlso (str.Length > 0))) AndAlso ((Not UIRichTextBox.InternalEditStream Is Nothing) AndAlso (Not UIRichTextBox.InternalStreamIn Is Nothing))) Then
Dim bytes As Byte()
Dim index As Integer = str.IndexOf(ChrW(0))
If (index <> -1) Then
str = str.Substring(0, index)
End If
If ((flags And &H10) <> 0) Then
bytes = Encoding.Unicode.GetBytes(str)
Else
bytes = Encoding.Default.GetBytes(str)
End If
Dim data As New System.IO.MemoryStream()
UIRichTextBox.InternalEditStream.SetValue(Me, data)
data.Write(bytes, 0, bytes.Length)
data.Position = 0
UIRichTextBox.InternalStreamIn.Invoke(Me, New Object() {data, flags})
Return True
End If
Return False
End Function
Private Function StreamOut(ByVal flags As Integer, ByRef result As String) As Boolean
If ((Me.IsHandleCreated AndAlso ((Not Me.IsDisposed) AndAlso (Not Me.Disposing))) AndAlso (Not UIRichTextBox.InternalStreamOut Is Nothing)) Then
Dim data As New System.IO.MemoryStream()
UIRichTextBox.InternalStreamOut.Invoke(Me, New Object() {data, flags, Me.m_includeCrLfs})
data.Position = 0
Dim length As Integer = CInt(data.Length)
Dim str As String = String.Empty
If (length > 0) Then
Dim buffer As Byte() = New Byte(length - 1) {}
data.Read(buffer, 0, length)
If ((flags And &H10) <> 0) Then
str = Encoding.Unicode.GetString(buffer, 0, buffer.Length)
Else
str = Encoding.Default.GetString(buffer, 0, buffer.Length)
End If
If ((Not String.IsNullOrEmpty(str)) AndAlso (str.Chars((str.Length - 1)) = ChrW(0))) Then
str = str.Substring(0, (str.Length - 1))
End If
End If
result = str
Return True
End If
Return False
End Function
Private Shared ReadOnly InternalEditStream As FieldInfo
Private Shared ReadOnly InternalStreamIn As MethodInfo
Private Shared ReadOnly InternalStreamOut As MethodInfo
Private m_includeCrLfs As Boolean
End Class
这篇关于如何将 RichTextBox 行尾从 Lf 更改为 CrLf的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!