WPF Standard Control Demo App › TextBox
TextBox Inputs
TextBox is the editable text input of WPF, for single-line fields and, with AcceptsReturn, multiline text.
When the text reaches the bound source
TextBox derives from TextBoxBase, which derives from Control. Its Text property binds two-way by default, and its default UpdateSourceTrigger is LostFocus: a bound source receives the text when the TextBox loses focus, not on every keystroke. Typing “abc” one character at a time wrote the source 3 times with UpdateSourceTrigger=PropertyChanged, and not at all with the default until the focus left the TextBox. Use PropertyChanged for a search box whose filter follows each keystroke. Controlling When TextBox Input Reaches the Source with UpdateSourceTrigger in WPF measures the difference between the triggers.
What applies only to typing
Several properties act only on what the user types. Treat them as input aids, not rules, and validate values that come from code or from a ViewModel separately.
MaxLength: the default 0 means no limit, and a negative value throwsArgumentException. WithMaxLength="5", typing “ABCDEFGH” left “ABCDE”. Text set from code or through a binding kept all eight letters.CharacterCasing: the default isNormal. WithUpper, typing “hello” gave “HELLO”, butText = "hello"from code stayed “hello”.AcceptsReturn: with the defaultFalse, Enter did not change the text; withTrue, it inserted a line break (\r\n).IsReadOnly: typed text was ignored, butSelectAll()still selected the text; with the text selected, Copy could execute while Cut and Paste could not. This suits logs or error details the user may need to copy. The default template has no trigger onIsReadOnly, and the background and border stayed the same colors as an editable TextBox. Add your own style trigger if users need to see the difference. How to Display Selectable, Copyable Read-Only Text in WPF compares this with other ways to show copyable text.
| case | Text after |
|---|---|
| MaxLength=5, typed "ABCDEFGH" | "ABCDE" |
| MaxLength=5, Text = "ABCDEFGH" from code | "ABCDEFGH" |
| MaxLength=5, Text bound to a source set to "ABCDEFGH" | "ABCDEFGH" |
| CharacterCasing=Upper, typed "hello" | "HELLO" |
| CharacterCasing=Upper, Text = "hello" from code | "hello" |
| IsReadOnly=True, typed "xyz" after "abc" | "abc" |
| IsReadOnly=True, SelectAll(): SelectedText | "abc" |
| AcceptsReturn=False, Enter between "a" and "b" | "ab" |
| AcceptsReturn=True, Enter between "a" and "b" | "a\r\nb" |
| Default: "abc" typed: source writes while typing; after focus leaves | 0 ((empty)); 1 (abc) |
| PropertyChanged: "abc" typed: source writes while typing; after focus leaves | 3 (abc); 3 (abc) |
| IsReadOnly: text after typing "x"; all selected: Copy / Cut / Paste can execute | error details; True / False / False |
Typed input compared with text set from code or a binding. Measured on .NET 10 / Windows 11.
Wrapping, alignment, and decorations
TextWrapping defaults to NoWrap. With two 26-letter words in a TextBox 150 wide, NoWrap kept one line 385 wide. Wrap produced 4 lines and broke inside the words, with 20 letters on the first line. WrapWithOverflow broke only between words: it produced 2 lines, and each word ran past the edge (190.86 wide in a 144-wide viewport). Choose WrapWithOverflow for text with long tokens that must not be split, such as paths or URLs, and Wrap when everything must stay inside the width. TextBox has no TextTrimming property; that is a TextBlock feature.
TextAlignment defaults to Left. With “123” in a TextBox 200 wide, the first character was at x = 3 with Left, 90.3 with Center, and 177.59 with Right.
TextDecorations can combine several lines: TextDecorations="Underline, Strikethrough" was converted into a collection of two decorations. SelectionOpacity defaults to 0.4.
Height: MinLines, MaxLines, and scroll bars
A multiline TextBox shows no scroll bar by default, because VerticalScrollBarVisibility and HorizontalScrollBarVisibility default to Hidden. With ten lines in a TextBox 60 high, the content was 159.6 high, but no bar appeared until VerticalScrollBarVisibility="Auto". In a StackPanel, which does not limit height, the same TextBox simply grew to 161.6. For notes and comments, combine AcceptsReturn="True", TextWrapping="Wrap", and VerticalScrollBarVisibility="Auto".
MaxLines is the most lines the TextBox grows to; the default is Int32.MaxValue. According to the documentation, MaxLines and MinLines have no effect when Height is set explicitly; the TextBoxes measured here had no Height. With AcceptsReturn, VerticalScrollBarVisibility="Auto", and ten lines of text, MaxLines 2, 4, and 6 gave heights of 33.92, 65.84, and 97.77, with a vertical scroll bar in each.
MinLines is the fewest lines the TextBox is tall; the default is 1. On .NET 10 it did not take effect when it was set before the TextBox was shown, as in XAML. An empty TextBox with MinLines="4" was one line tall (17.96), the same as with 1, 2, or 6. It took effect once the text changed after the TextBox was displayed: the height became 65.84, four lines. Setting MinLines after the TextBox was displayed applied it at once, and so did setting it in a Loaded handler when XAML did not set it. With MinLines="4" also in XAML, setting 4 again in Loaded did not change the value, and the TextBox stayed one line tall. If it matters on first display, set it after loading and not in XAML, on a TextBox without an explicit Height.
ScrollToEnd() on the UI thread scrolled to the bottom (VerticalOffset 101.6, equal to the scrollable height). Called from a worker thread it threw InvalidOperationException; call it through the Dispatcher when text is appended from another thread.
| case | measured |
|---|---|
| TextWrapping=NoWrap, width 150, demo text | 1 lines, line 1 has 53 chars, extent 385.01 / viewport 144 |
| TextWrapping=Wrap, width 150, demo text | 4 lines, line 1 has 20 chars, extent 143.4 / viewport 144 |
| TextWrapping=WrapWithOverflow, width 150, demo text | 2 lines, line 1 has 26 chars, extent 190.86 / viewport 144 |
| MinLines=1, empty | height 17.96 |
| MinLines=2, empty | height 17.96 |
| MinLines=4, empty | height 17.96 |
| MinLines=6, empty | height 17.96 |
| MinLines=4, TextWrapping=Wrap, empty | height 17.96 |
| MinLines=4, one line of text | height 17.96 |
| MinLines=4, empty, in a 150 x 300 Grid, Top | height 17.96 |
| MinLines="4" written in XAML (the demo app's markup), empty | height 17.96 |
| then Text changed / then FontSize changed | height 65.84 / 71.16 |
| MinLines=4 set after showing: height before / after / + MaxLines=10 | 17.96 / 65.84 / 65.84 |
| MinLines=4 set in a Loaded handler, not in XAML: height | 65.84 |
| MinLines="4" in XAML, and 4 set again in a Loaded handler: height | 17.96 |
| MaxLines=2, 10 lines | height 33.92, vertical bar Visible |
| MaxLines=4, 10 lines | height 65.84, vertical bar Visible |
| MaxLines=6, 10 lines | height 97.77, vertical bar Visible |
| Height=60, 10 lines, VerticalScrollBarVisibility not set | bar Collapsed, extent 159.6 / viewport 58 |
| Height=60, 10 lines, VerticalScrollBarVisibility Auto | bar Visible, extent 159.6 / viewport 58 |
| AcceptsReturn, 10 lines, inside a StackPanel (no height limit) | height 161.6 |
| TextAlignment=Left, "123" in width 200 | first character at x 3 |
| TextAlignment=Center, "123" in width 200 | first character at x 90.3 |
| TextAlignment=Right, "123" in width 200 | first character at x 177.59 |
| TextDecorations="Underline, Strikethrough" | 2 decorations: Underline, Strikethrough |
| ScrollToEnd() from a worker thread | InvalidOperationException |
| ScrollToEnd() on the UI thread: VerticalOffset / scrollable height | 101.6 / 101.6 |
| default template: IsReadOnly triggers / Background, BorderBrush | 0 / #FFFFFFFF #FFABADB3 (normal), #FFFFFFFF #FFABADB3 (read-only) |
Wrapping, line limits, scroll bars, alignment, and ScrollToEnd. Measured on .NET 10 / Windows 11.
Trying it in the demo app

The TextBox page of the demo app has a section for each of Text, TextWrapping, TextDecorations, TextAlignment, MaxLength, MaxLines, MinLines, and CharacterCasing. In several sections, one source text box feeds the others through bindings, so you can compare the settings with the same text. Because of that, the MaxLength="5" and MaxLength="10" boxes show text past their limit uncut, and the MinLines boxes start one line tall and grow when you type in the source box. The “Show Code” link under each section displays its XAML. The following XAML is the Text section (TextBoxUsageControl.xaml), with the styles and the surrounding GroupBoxes left out and the namespace declarations added. The three text boxes, with UpdateSourceTrigger set to Default, LostFocus, and PropertyChanged, write to the same TextBlock at different times: the first two when you leave the box, and the third on every keystroke:
<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextBox x:Name="UpdateSourceTriggerDefaultTextBox"
Text="{Binding Text, ElementName=UpdateSourceTrigger, UpdateSourceTrigger=Default}" />
<TextBox x:Name="UpdateSourceTriggerLostFocusTextBox"
Text="{Binding Text, ElementName=UpdateSourceTrigger, UpdateSourceTrigger=LostFocus}" />
<TextBox x:Name="UpdateSourceTriggerPropertyChangedTextBox"
Text="{Binding Text, ElementName=UpdateSourceTrigger, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock x:Name="UpdateSourceTrigger" />
</StackPanel>
Related controls and articles
- Controlling When TextBox Input Reaches the Source with UpdateSourceTrigger in WPF — when each trigger updates the source.
- Calling TextBox UpdateSource from the View in WPF: Implementation and Pitfalls — updating the source explicitly.
- How to Display Selectable, Copyable Read-Only Text in WPF — read-only text the user can select.
- PasswordBox — masked input for passwords.
- TextBlock — displays text without editing.
Source code and how it was measured
Every behavior on this page was measured by running it on .NET 10 / Windows 11, using TextBoxDemoScene in this site’s screenshot tool. Typing was reproduced one character at a time with TextCompositionManager, which delivers text through the same TextInput path as the keyboard, and the Enter key by sending a key event to a displayed window. Heights, widths, and positions on this page are the values on the measuring machine; they depend on the font and display scaling.