#940 – Easy Selection of Entire Words in a TextBox

By default, as the user drags the mouse in a TextBox while holding the left mouse button down, text is selected one character at a time.

For example, in the TextBox shown below, if I click in the middle of the word “years” and drag the cursor into the middle of the word “later”, a portion of each word is selected.

940-001

 

If you want a user to easily select entire words within the text, you can set the AutoWordSelection property of the TextBox to true.  Now, as I drag the cursor into the second word, both words are automatically selected.

940-002

 

Even with auto word selection enabled, the user can select a portion of the word by selecting the full word and then moving the cursor backwards.

#939 – Retrieving Individual Lines of Text from a TextBox

The LineCount property of a TextBox can be used to retrieve the current number of lines of text in a TextBox.  If the text wraps to multiple lines, this property will reflect the visible number of wrapped lines that the user sees.

The TextBox.GetLineText method allows reading an individual line of text based on a 0-based index.

Assume that we have a TextBox that wraps some text:

        <TextBox Name="txtTest" Margin="5" Height="100"
            Text="{Binding SomeText}"
            TextWrapping="Wrap"
            SelectionBrush="Purple"
            VerticalScrollBarVisibility="Auto"/>
        <Button Content="Inspect" Click="Button_Click"
            HorizontalAlignment="Center" Padding="10,5"/>

We can then read each visible line when the button is clicked.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sbInfo = new StringBuilder(string.Format("# lines = {0}", txtTest.LineCount));
            sbInfo.AppendLine();

            for (int i = 0; i < txtTest.LineCount; i++)
                sbInfo.AppendLine(txtTest.GetLineText(i));

            MessageBox.Show(sbInfo.ToString());
        }

939-001
If we change the size of the TextBox, causing the lines to wrap differently, the LineCount will change.

939-002

#938 – Changing the Selected Text Color in a TextBox

You can change the color of the brush that is used to show selected text in a TextBox by setting the SelectionBrush property.  You’ll typically set this property in XAML to the name of the color that you want the text selection rendered in.  This property defaults to a SolidColorBrush whose color is hex 3399FF (R=51, G=153, B=255), or light blue.

        <TextBox Name="txtTest" Margin="5" Height="100"
            Text="{Binding SomeText}"
            TextWrapping="Wrap"
            SelectionBrush="Purple"
            VerticalScrollBarVisibility="Auto"/>

938-001
The opacity used by the selection brush defaults to 0.4, but you can set it to be more (>0.4) or less (<0.4) opaque by changing the SelectionOpacity property.

        <TextBox Name="txtTest" Margin="5" Height="100"
            Text="{Binding SomeText}"
            TextWrapping="Wrap"
            SelectionBrush="Purple"
            SelectionOpacity="0.2"
            VerticalScrollBarVisibility="Auto"/>

938-002

#937 – Selecting Text in a TextBox from Code

You can select text in a TextBox from code by using the Select method.  This method accepts the following two parameters:

  • start – 0-based index for start of selection (int)
  • length – number of characters to select (int)

Note that if the TextBox doesn’t currently have focus, the selected text will not be highlighted.

Assume that we have a TextBox, some labels displaying selected text and a Button:

        <TextBox Name="txtTest" Margin="5" Height="100"
            Text="{Binding SomeText}"
            TextWrapping="Wrap"
            VerticalScrollBarVisibility="Auto"
            SelectionChanged="TextBox_SelectionChanged"/>
        <Label Content="{Binding SelectedText}"/>
        <StackPanel Orientation="Horizontal">
            <Label Content="{Binding SelectionStart}"/>
            <Label Content="{Binding SelectionLength}"/>
        </StackPanel>
        <Button Content="Select Something" Click="Button_Click"/>

The code below then selects some text when the button is pressed.

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Select 10 characters, starting 6th character
            txtTest.Select(5, 10);

            // Give focus back to TextBox, so that it
            // highlights selected text
            txtTest.Focus();
        }

937-001

#936 – TextBox Properties that Reflect Currently Selected Text

The following properties of a TextBox are updated whenever the user changes the currently selected text in a TextBox.

  • SelectedText – the currently selected text (string)
  • SelectionStart – 0-based index into the Text property for the start of the selection  (int)
  • SelectionLength – number of characters selected (int)

The SelectionChanged event will fire whenever the currently selected text changes.

Below, we wire up the SelectionChanged event, capture the values of these properties, and then bind to those values.

        <TextBox Margin="5" Height="100"
            Text="{Binding SomeText}"
            TextWrapping="Wrap"
            VerticalScrollBarVisibility="Auto"
            SelectionChanged="TextBox_SelectionChanged"/>
        <Label Content="{Binding SelectedText}"/>
        <StackPanel Orientation="Horizontal">
            <Label Content="{Binding SelectionStart}"/>
            <Label Content="{Binding SelectionLength}"/>
        </StackPanel>
        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        public string SelectedText { get; set; }
        public int SelectionStart { get; set; }
        public int SelectionLength { get; set; }

        private void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
        {
            SelectedText = ((TextBox)sender).SelectedText;
            SelectionStart = ((TextBox)sender).SelectionStart;
            SelectionLength = ((TextBox)sender).SelectionLength;

            RaisePropertyChanged("SelectedText");
            RaisePropertyChanged("SelectionStart");
            RaisePropertyChanged("SelectionLength");
        }

936-001

#935 – Setting an Undo Limit for a TextBox

By default, a TextBox control has an undo limit of 100.  That is, it keeps track of the most recent 100 edits that you’ve made, allowing you to undo them one at a time.

You can change the number of operations that the TextBox remembers by setting its UndoLimit property.  For example, if you set this value to 3, the TextBox will only allow you to undo the most recent three edits.

You may want to increase the value of UndoLimit so that the user of your application has the ability to undo a larger number of recent operations.

    <TextBox Margin="5" UndoLimit="1000"
        Text="{Binding SomeText}"
        TextWrapping="Wrap"
        VerticalScrollBarVisibility="Auto"/>

On the other hand, you may want to reduce the value of UndoLimit so that your application does need to allocate memory for all of the recent changes to a TextBox.

#934 – TextBox Has Built-In Undo Functionality

The TextBox control in WPF has built-in Undo and Redo functionality, allowing you to undo changes to the content of the TextBox or to re-apply (redo) changes that you’ve undone.

Assume that you have a TextBox with some text:

934-001

Now assume that you double-click to select the first word and then press Delete to delete it.

934-002

Do this two more times, so that you’ve delete the first three words of the text, one at a time.

934-003

You’ve now made three distinct changes to the text in the TextBox, one at a time.  You can delete the most recent change by pressing Ctrl+Z, which executes an undo operation.  This will restore the word that was most recently deleted.

934-004

You can press Ctrl+Z two more times, restoring the other words that you deleted.

934-005

You can redo a change (e.g. delete a word) by pressing Ctrl+Y.

934-006

#933 – Cut/Copy/Paste Functionality in a TextBox

Cut, Copy and Paste functionality is automatically enabled for the text within a TextBox control.

You can select text in a TextBox by

  • Left-clicking and dragging with the mouse
  • Double-clicking to select a word
  • Moving the arrow keys while holding down the Shift key
  • Pressing Ctrl+A to select all text in the TextBox

933-001

 

With text selected, you can Cut or Copy selected text by

  • Right-clicking and selecting Cut or Copy from the context menu
  • Pressing Ctrl+X to Cut text (remove from TextBox and add to clipboard)
  • Pressing Ctrl+C to Copy text (add to clipboard without removing)

933-002

You can Paste text from the clipboard into the TextBox at the current cursor location by

  • Right-clicking and selecting Paste from the context menu
  • Pressing Ctrl+V to Paste text

If you currently have text selected, doing a Paste operation will replace the selected text with text from the clipboard.

933-003

 

#932 – Making a TextBox Read-Only or Disabled

You can control a couple of different things with the IsEnabled and IsReadOnly properties of a TextBox.

  • IsEnabled – When false, user can’t interact with the control in any way and the control is greyed out.  (Default is true)
  • IsReadOnly – When true, user can’t edit or enter text, but can still scroll, select text and copy.

Typical combinations:

  • IsEnabledtrue, IsReadOnly = false — standard behavior, editable text
  • IsEnabled = true, IsReadOnly = true — read-only text, user can scroll/copy
  • IsEnabled = false — user can’t interact with TextBox at all
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBox Name="txtMain" Margin="5"
                 Text="{Binding SomeText}"
                 TextWrapping="Wrap"
                 VerticalScrollBarVisibility="Auto"
                 IsReadOnly="{Binding ElementName=chkReadOnly, Path=IsChecked}"
                 IsEnabled="{Binding ElementName=chkEnabled, Path=IsChecked}"/>
        <StackPanel Orientation="Horizontal" Grid.Row="1">
            <CheckBox Name="chkReadOnly" Content="IsReadOnly" />
            <CheckBox Name="chkEnabled" Content="IsEnabled" />
        </StackPanel>
    </Grid>

932-001
932-002
932-003

#931 – Scrolling Text in a TextBox from Code

If you want to programmatically scroll the text within a TextBox control, you can use any of the scrolling methods available to a ScrollViewer.  Specifically:

  • Methods for scrolling vertically
    • LineUp / LineDown
    • PageUp / PageDown
    • ScrollToHome / ScrollToEnd
  • Methods for scrolling horizontally
    • LineLeft / LineRight
    • PageLeft / PageRight
    • ScrollToLeftEnd / ScrollToRightEnd

These methods scroll content as if the user had clicked on the corresponding scrollbar–either on the arrows at the end (single line) or in the empty space (single page).

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <StackPanel>
            <Button Content="PageUp" Click="btnPageUp_Click"/>
            <Button Content="LineUp" Click="btnLineUp_Click"/>
            <Button Content="LineDown" Click="btnLineDown_Click"/>
            <Button Content="PageDown" Click="btnPageDown_Click"/>
        </StackPanel>
        <TextBox Name="txtMain" Grid.Column="1" Margin="5"
                 Text="{Binding SomeText}"
                 TextWrapping="NoWrap"
                 AcceptsReturn="True"
                 VerticalScrollBarVisibility="Auto"
                 HorizontalScrollBarVisibility="Auto"/>
        <StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="1">
            <Button Content="PageLeft"  Click="btnPageLeft_Click"/>
            <Button Content="LineLeft" Click="btnLineLeft_Click"/>
            <Button Content="LineRight" Click="btnLineRight_Click"/>
            <Button Content="PageRight" Click="btnPageRight_Click"/>
        </StackPanel>
    </Grid>

Event handlers would follow the form:

        private void btnPageUp_Click(object sender, RoutedEventArgs e)
        {
            txtMain.PageUp();
        }

931-001