如何创建在每行之前显示撇号的多行文本框

时间:2009-11-25 14:40:08

标签: c# .net wpf xaml wpf-controls

我想要一个多行文本框,在每行之前和之后显示撇号。 所以文本框看起来像:

" Hello this  "
" is a funny  "
" string test "

或者例如:

// This is
// a muliline
// comment.

编辑:这些特殊字符必须是只读的,如果用户从文本框中复制文本,则这些字符应

3 个答案:

答案 0 :(得分:2)

使用两个直接叠放的文本框非常容易。后面的是一个普通的文本框,带有额外的填充和透明文本。前面的一个有额外的字符但隐藏了边框,IsHitTestVisible=FalseFocusable=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计算给定此值的适当边距。 / p>

注意:当涉及文本选择的颜色方案时,这种解决方案非常不令人满意。这可以修复,但需要更复杂的解决方案:后部文本框相同但文本不可见。前面的文本框被替换为RichTextBox(或TextBlock),其内容被动态计算为具有额外字符的文本,但常规文本是透明的。因为它是RichTextBox,所以可以看到额外的字符,而其他字符是透明的。

答案 1 :(得分:1)

你能不能简单地使用继承创建用户定义的文本框,并将multiline属性设置为true,并且文本上的一些特殊代码更改了事件以检查每行的第一个和最后一个索引以确保它在那里有撇号?或者如果没有办法迭代行,你能在每个chr(11)或chr(13)之前和之后观察角色吗?

这对winforms来说并不困难,但我不确定WPF。

~~~~~~~~~~~~~~~~~~~~~~~~~编辑1:11/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

答案 2 :(得分:0)

我想说你最好的办法就是实现自己的文本框(继承自文本框本身作为基础,这样你就可以免费获得所有功能)并覆盖绘图代码并自己写出每一行(前/后)在写出每一行时用撇号。)