简体   繁体   中英

How to create multiline textbox which shows apostrophe before each line

I want a multiline textbox which shows apostrophes before and after each line. So that the textbox looks like:

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

Or for example:

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

Edit: These special characters must be readonly and if the user copies text from the textbox these characters should not be included.

This is very easy using two textboxes laid directly over one another. The rear one is a normal textbox with extra padding and transparent text. The front one has your extra characters but has its borders hidden and is IsHitTestVisible=False and Focusable=False so it doesn't interact with the user. The user interacts exclusively with the rear textbox but the front textbox is the one that displays the text. A binding with a value converter keeps the front textbox displaying exactly what the rear textbox displays, plus the extra characters.

This is how it would look:

<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 is a simple IValueConverter class that implements the Convert method by taking the given string, appending quotes or // or whatever to it, and returning the result.

Note that I hard-coded a left and right margin of 10 units on the rear textbox, which assumes a particular width for the quote characters. This should be exactly the width of the added characters to make the text line up correctly. You want to get this right, or your caret and text selection positioning will be wrong. Also note that the correct value will change as you vary your font size and your choice of extra characters.

An easy alternative to hard-coding the margin would be to set it to a multi-binding on FontSize, FontFamily, FontWeight , etc, then use a IMultiValueConverter to compute the proper margin given this these values.

Note: This solution is slighly unsatisfactory when it comes to the color scheme for text selection. This can be fixed, but it requires a more complex solution: The rear text box is the same but its text is not invisible. The front text box is replaced with a RichTextBox (or TextBlock) whose content is computed dynamically to be the text with extra characters, but the regular text transparent. Because it is a RichTextBox the extra characters can be visible while the others are transparent.

Can you not simply create a user defined textbox using inheritance with the multiline property set to true, and some special code on the text changed event to check the first and last index on each line to ensure it has an apostrophe there? or if there is no way to iterate lines, can you just watch the character before and after every chr(11) or chr(13)?

This wouldn't be difficult with winforms, i'm not sure about WPF however.

~~~~~~~~~~~~~~~~~~~~~~~~~Edit 1: 11/25/2009 9:12 AM CT~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If you would like it so that the user cannot edit or mess with the quotes, then you could write specific code in the KeyPressed event handler (or override the OnKeyPressed function if you are doing an inherited control) to keep them from adding characters before or after a chr(11) or chr(13), and add it back immediately if they attempt to delete it, and cancel invalid keystrokes.

I've written code similar to this in VB .NET for a money text box field. It may help you to understand what i'm talking about, and it may assist you in what you are doing:

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

我想说,最好的选择是实现自己的文本框(从文本框本身继承而来,因此您可以免费获得所有功能),并覆盖绘图代码并自己写出每一行(在输入之前/之后添加)在写出每一行时都用单引号引起来)。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM