[英]How to create multiline textbox which shows apostrophe before each line
我想要一个多行文本框,该文本框在每行之前和之后显示撇号。 这样文本框看起来像:
" Hello this "
" is a funny "
" string test "
或者例如:
// This is
// a muliline
// comment.
编辑:这些特殊字符必须是只读的,如果从文本框中的用户复制文本这些字符不应该被包括在内。
使用两个彼此直接放置的文本框,这非常容易。 后面的是一个普通的文本框,带有额外的填充和透明文本。 前一个有您的多余字符,但边框已隐藏,并且IsHitTestVisible=False
和Focusable=False
因此它不会与用户交互。 用户只与后文本框交互,而前文本框是显示文本的文本框。 与值转换器的绑定使前文本框准确显示后文本框显示的内容,以及额外的字符。
它是这样的:
<ControlTemplate x:Key="TextBoxWithExtraCharacters" TargetType="{x:Type TextBox}">
<ControlTemplate.Resources>
<!-- Remove the border from the inner textboxes -->
<ControlTemplate TargetType="{x:Type TextBox}">
<Decorator x:Name="PART_Content" />
</ControlTemplate>
</ControlTemplate.Resources>
<!-- Now add our own border -->
<Border
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<!-- Scrolling must happen at this level so both text boxes scroll simultaneously -->
<ScrollViewer>
<Grid>
<!-- Rear textbox provides editing and user interaction but the text is transparent -->
<TextBox
Margin="10,0,10,0"
Foreground="Transparent"
Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}"
Background="{x:Null}"
IsReadOnly="{TemplateBinding IsReadOnly}"
IsUndoEnabled="{TemplateBinding IsUndoEnabled}"
AcceptsReturn="{TemplateBinding AcceptsReturn}"
AcceptsTab="{TemplateBinding AcceptsTab}"
/>
<!-- Front textbox displays modified text but does not interact with user -->
<TextBox
IsHitTestVisible="false"
Focusable="false"
Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent},
Converter={x:Static ExtraCharacterConverter.Instance}"
Background="{x:Null}"
IsReadOnly="{TemplateBinding IsReadOnly}"
IsUndoEnabled="{TemplateBinding IsUndoEnabled}"
AcceptsReturn="{TemplateBinding AcceptsReturn}"
AcceptsTab="{TemplateBinding AcceptsTab}"
/>
</Grid>
</ScrollViewer>
</Border>
</ControlTemplate>
ExtraCharacterConverter是一个简单的IValueConverter
类,该类通过获取给定的字符串,在其后加上引号或//或其他内容并返回结果来实现Convert
方法。
请注意,我在后文本框上硬编码了10个单位的左右边距,假定引号字符的宽度是特定的。 这应该恰好是所添加字符的宽度,以使文本正确对齐。 您想得到正确的选择,否则插入符号和文本选择的位置将是错误的。 还要注意,随着字体大小和其他字符的选择,正确的值也会改变。
硬编码裕度的一个简单替代方法是将其设置为FontSize, FontFamily, FontWeight
等的多重绑定,然后使用IMultiValueConverter
来给定这些值来计算适当的裕度。
注意:当涉及到用于文本选择的配色方案时,此解决方案绝对不能令人满意。 此问题可以解决,但需要更复杂的解决方案:后面的文本框相同,但其文本不可见。 前面的文本框替换为RichTextBox(或TextBlock),其内容被动态计算为带有额外字符的文本,但常规文本透明。 因为它是RichTextBox,所以可以看到其他字符,而其他字符是透明的。
您是否不能简单地使用multiline属性设置为true的继承来创建用户定义的文本框,并在文本更改事件上使用一些特殊代码来检查每行的第一个和最后一个索引,以确保该行上有撇号? 或者,如果没有办法迭代行,您是否可以只在每个chr(11)或chr(13)之前和之后观看字符?
对于winforms,这并不困难,但是我不确定WPF。
~~~~~~~~~~~~~~~~~~~~~~~~编辑1:1/25/2009 9:12 AM CT ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
如果您希望用户不能对其进行编辑或使引号混乱,则可以在KeyPressed事件处理程序中编写特定的代码(如果正在执行继承的控件,则可以重写OnKeyPressed函数),以防止它们在之前或之后添加字符。在chr(11)或chr(13)之后,如果他们试图删除它并取消无效的击键,请立即将其重新添加。
我在VB .NET中为钱文本框字段编写了与此类似的代码。 它可以帮助您了解我在说什么,也可以帮助您进行操作:
Protected Overrides Sub OnMouseClick(ByVal e As System.Windows.Forms.MouseEventArgs)
If Me.SelectionStart = 0 Then
Me.SelectionStart = Me.Text.Length
End If
End Sub
Protected Overrides Sub OnTextChanged(ByVal e As System.EventArgs)
If Not Me.Text.IndexOf("$") = 0 Then
Me.Text = "$" + Me.Text.Replace("$", "")
End If
If Me.SelectionStart = 0 Then
Me.SelectionStart = Me.Text.Length
End If
End Sub
Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
If NOT ((Char.IsDigit(e.KeyChar) Or (e.KeyChar = CChar(".") And Not Me.Text.Contains(".")) Or Char.IsControl(e.KeyChar)) And (Not Char.IsDigit(e.KeyChar) Or (Me.SelectionStart <= Me.Text.IndexOf(".") + 2 Or Me.Text.IndexOf(".") = -1))) Then
e.Handled = True
End If
End Sub
我想说,最好的选择是实现自己的文本框(从文本框本身继承而来,因此您可以免费获得所有功能),并覆盖绘图代码并自己写出每一行(在输入之前/之后添加)在写出每一行时都用单引号引起来)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.