WPF 標準コントロールデモアプリ › TextBox
TextBox Inputs
TextBox は WPF の編集可能なテキスト入力で、1 行の入力欄にも、AcceptsReturn を使った複数行のテキストにも使います。
入力がバインドしたソースへ届くタイミング
TextBox は TextBoxBase を、TextBoxBase は Control を継承しています。Text プロパティは既定で TwoWay にバインドされ、既定の UpdateSourceTrigger は LostFocus です。つまり、バインドしたソースに値が届くのは、キーを押すたびではなく、TextBox がフォーカスを失ったときです。「abc」を 1 文字ずつ入力すると、UpdateSourceTrigger=PropertyChanged ではソースへの書き込みが 3 回あり、既定ではフォーカスが移るまで 1 回もありませんでした。キーを押すたびに絞り込む検索ボックスには PropertyChanged を使います。トリガーごとの違いはWPF TextBox の UpdateSourceTrigger で入力がソースへ反映されるタイミングを制御するで実測しています。
入力にだけ働くもの
いくつかのプロパティは、ユーザーが入力した文字にだけ働きます。規則ではなく入力の補助と考え、コードや ViewModel から入る値は別に検証します。
MaxLength— 既定値の 0 は無制限で、負の値を設定するとArgumentExceptionが発生します。MaxLength="5"で “ABCDEFGH” と入力すると “ABCDE” になりました。コードやバインドで設定した文字列は、8 文字すべてが残りました。CharacterCasing— 既定値はNormalです。Upperで “hello” と入力すると “HELLO” になりましたが、コードからText = "hello"と設定すると “hello” のままでした。AcceptsReturn— 既定値のFalseでは、Enter キーを押しても文字列は変わりませんでした。Trueでは改行(\r\n)が入りました。IsReadOnly— 入力した文字は無視されましたが、SelectAll()で文字列を選択でき、選択した状態ではコピーは実行でき、切り取りと貼り付けは実行できませんでした。ユーザーがコピーする可能性のあるログやエラーの詳細の表示に向きます。既定のテンプレートにはIsReadOnlyのトリガーがなく、背景と枠線は編集可能な TextBox と同じ色のままでした。編集できないことを見た目で示したい場合は、自分でスタイルのトリガーを加えます。コピーできる文字列を表示する他の方法との比較は、WPFで編集不可のままテキストを選択・コピー可能に表示する方法で扱っています。
| 条件 | 操作後の Text |
|---|---|
| MaxLength=5、"ABCDEFGH" を入力 | "ABCDE" |
| MaxLength=5、コードから Text = "ABCDEFGH" | "ABCDEFGH" |
| MaxLength=5、"ABCDEFGH" にしたソースへ Text をバインド | "ABCDEFGH" |
| CharacterCasing=Upper、"hello" を入力 | "HELLO" |
| CharacterCasing=Upper、コードから Text = "hello" | "hello" |
| IsReadOnly=True、"abc" の後に "xyz" を入力 | "abc" |
| IsReadOnly=True、SelectAll() の後の SelectedText | "abc" |
| AcceptsReturn=False、"a" と "b" の間で Enter | "ab" |
| AcceptsReturn=True、"a" と "b" の間で Enter | "a\r\nb" |
| Default: "abc" を入力。入力中のソースへの書き込み、フォーカスが移った後 | 0 (空)、1 (abc) |
| PropertyChanged: "abc" を入力。入力中のソースへの書き込み、フォーカスが移った後 | 3 (abc)、3 (abc) |
| IsReadOnly: "x" を入力した後の Text、全選択で Copy / Cut / Paste が実行できるか | error details、True / False / False |
キー入力と、コードやバインドで設定した文字列の比較。.NET 10 / Windows 11 で計測。
折り返し・配置・装飾
TextWrapping の既定値は NoWrap です。幅 150 の TextBox に 26 文字の単語を 2 つ並べると、NoWrap は 1 行のまま幅 385 になりました。Wrap は単語の途中でも折り返して 4 行になり、1 行目は 20 文字でした。WrapWithOverflow は単語の区切りでだけ折り返して 2 行になり、単語が右端からはみ出しました(表示幅 144 に対して 190.86)。パスや URL など途中で折り返したくない文字列には WrapWithOverflow を、すべてを幅に収めたい場合は Wrap を選びます。TextBox には TextTrimming プロパティはありません。これは TextBlock の機能です。
TextAlignment の既定値は Left です。幅 200 の TextBox に “123” を入れると、1 文字目の位置は Left で x = 3、Center で 90.3、Right で 177.59 でした。
TextDecorations は複数の線を組み合わせられ、TextDecorations="Underline, Strikethrough" は 2 つの装飾のコレクションに変換されました。SelectionOpacity の既定値は 0.4 です。
高さ:MinLines・MaxLines・スクロールバー
複数行の TextBox にも、既定ではスクロールバーは出ません。VerticalScrollBarVisibility と HorizontalScrollBarVisibility の既定値が Hidden のためです。高さ 60 の TextBox に 10 行を入れると内容の高さは 159.6 になりましたが、VerticalScrollBarVisibility="Auto" にするまでスクロールバーは出ませんでした。高さを制限しない StackPanel の中では、同じ TextBox は高さ 161.6 まで伸びました。メモやコメントの欄には、AcceptsReturn="True"・TextWrapping="Wrap"・VerticalScrollBarVisibility="Auto" を組み合わせます。
MaxLines は TextBox が広がる最大の行数で、既定値は Int32.MaxValue です。ドキュメントによれば、Height を明示した TextBox では MaxLines も MinLines も効きません。ここで測った TextBox には Height を指定していません。AcceptsReturn、VerticalScrollBarVisibility="Auto" で 10 行の文字列を入れると、MaxLines が 2・4・6 のときの高さは 33.92・65.84・97.77 になり、いずれも縦のスクロールバーが表示されました。
MinLines は TextBox の最小の行数で、既定値は 1 です。.NET 10 では、XAML のように表示前に設定した値は効きませんでした。空の TextBox に MinLines="4" を指定しても、高さは 1 行分(17.96)で、1・2・6 を指定した場合と同じでした。表示後に文字列が変わると効き、高さは 4 行分の 65.84 になりました。表示後に MinLines を設定するとすぐに効き、XAML で指定していなければ Loaded のハンドラーで設定しても効きました。XAML にも MinLines="4" があると、Loaded で 4 を設定し直しても値は変わらず、高さは 1 行分のままでした。最初の表示で効かせたいなら、Height を明示していない TextBox で、XAML では指定せず、読み込み後に設定します。
ScrollToEnd() は、UI スレッドから呼ぶと末尾までスクロールしました(VerticalOffset 101.6、スクロールできる高さと同じ)。ワーカースレッドから呼ぶと InvalidOperationException が発生しました。別のスレッドから文字列を追加する場合は、Dispatcher を通して呼びます。
| 条件 | 計測値 |
|---|---|
| TextWrapping=NoWrap、幅 150、デモの文字列 | 1 行、1 行目は 53 文字、内容の幅 385.01 / 表示幅 144 |
| TextWrapping=Wrap、幅 150、デモの文字列 | 4 行、1 行目は 20 文字、内容の幅 143.4 / 表示幅 144 |
| TextWrapping=WrapWithOverflow、幅 150、デモの文字列 | 2 行、1 行目は 26 文字、内容の幅 190.86 / 表示幅 144 |
| MinLines=1、空 | 高さ 17.96 |
| MinLines=2、空 | 高さ 17.96 |
| MinLines=4、空 | 高さ 17.96 |
| MinLines=6、空 | 高さ 17.96 |
| MinLines=4、TextWrapping=Wrap、空 | 高さ 17.96 |
| MinLines=4、1 行の文字列 | 高さ 17.96 |
| MinLines=4、空、150 x 300 の Grid の中で Top | 高さ 17.96 |
| XAML に MinLines="4"(デモアプリのマークアップ)、空 | 高さ 17.96 |
| 続けて Text を変更 / FontSize を変更 | 高さ 65.84 / 71.16 |
| 表示後に MinLines=4 を設定: 設定前 / 設定後 / MaxLines=10 を足した後の高さ | 17.96 / 65.84 / 65.84 |
| XAML ではなく Loaded ハンドラーで MinLines=4: 高さ | 65.84 |
| XAML に MinLines="4"、Loaded ハンドラーでも 4 を設定: 高さ | 17.96 |
| MaxLines=2、10 行 | 高さ 33.92、縦のバー Visible |
| MaxLines=4、10 行 | 高さ 65.84、縦のバー Visible |
| MaxLines=6、10 行 | 高さ 97.77、縦のバー Visible |
| Height=60、10 行、VerticalScrollBarVisibility 指定なし | バー Collapsed、内容の高さ 159.6 / 表示の高さ 58 |
| Height=60、10 行、VerticalScrollBarVisibility Auto | バー Visible、内容の高さ 159.6 / 表示の高さ 58 |
| AcceptsReturn、10 行、StackPanel の中(高さの制限なし) | 高さ 161.6 |
| TextAlignment=Left、幅 200 に "123" | 1 文字目の x 座標 3 |
| TextAlignment=Center、幅 200 に "123" | 1 文字目の x 座標 90.3 |
| TextAlignment=Right、幅 200 に "123" | 1 文字目の x 座標 177.59 |
| TextDecorations="Underline, Strikethrough" | 装飾 2 個: Underline, Strikethrough |
| ワーカースレッドから ScrollToEnd() | InvalidOperationException |
| UI スレッドで ScrollToEnd(): VerticalOffset / スクロールできる高さ | 101.6 / 101.6 |
| 既定のテンプレート: IsReadOnly のトリガー数 / Background、BorderBrush | 0 / #FFFFFFFF #FFABADB3(通常)、#FFFFFFFF #FFABADB3(読み取り専用) |
折り返し、行数の制限、スクロールバー、配置、ScrollToEnd。.NET 10 / Windows 11 で計測。
デモアプリで試す

デモアプリの TextBox のページには、Text、TextWrapping、TextDecorations、TextAlignment、MaxLength、MaxLines、MinLines、CharacterCasing の欄があります。いくつかの欄では 1 つの入力欄の文字列をバインドで複数のテキストボックスに流しており、同じ文字列で設定を比べられます。そのため、MaxLength="5" と MaxLength="10" の欄には上限を超えた文字列もそのまま表示され、MinLines の欄は最初はどれも 1 行の高さで、入力欄に文字を入れると広がります。各欄の下の「Show Code」リンクで、その欄の XAML を表示できます。次の XAML は、Text の欄(TextBoxUsageControl.xaml)から、スタイルと周囲の GroupBox を省き、名前空間の宣言を加えたものです。UpdateSourceTrigger をそれぞれ Default・LostFocus・PropertyChanged にした 3 つのテキストボックスが、同じ TextBlock へ異なるタイミングで書き込みます。前の 2 つはテキストボックスから離れたときに、3 つ目はキーを押すたびに書き込みます。
<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>
関連するコントロールと記事
- WPF TextBox の UpdateSourceTrigger で入力がソースへ反映されるタイミングを制御する — トリガーごとにソースが更新されるタイミングを扱います。
- WPF で TextBox の UpdateSource を View から呼び出すときの落とし穴と実装 — ソースを明示的に更新する方法を扱います。
- WPFで編集不可のままテキストを選択・コピー可能に表示する方法 — 選択できる読み取り専用の文字列を扱います。
- PasswordBox — パスワード用の、伏せ字で表示する入力欄です。
- TextBlock — 編集せずに文字列を表示します。
ソースコードと計測の方法
このページの挙動の記述は、すべて .NET 10 / Windows 11 で実際に動かして確かめたものです。計測には、このサイトのスクリーンショット生成ツールの TextBoxDemoScene を使いました。文字の入力は、キーボードと同じ TextInput の経路で文字を届ける TextCompositionManager で 1 文字ずつ、Enter キーは表示したウィンドウへキーのイベントを送って再現しています。このページの高さ・幅・位置は計測した環境での値で、フォントや表示スケールによって変わります。