Windows Presentation Foundation (WPF) のデータバインディングにおいて、UI入力をデータに自動反映させる双方向バインディングについて学びます。
前回は「データ→UI」の単方向同期を実装しましたが、今回は「UI→データ」も含めた双方向同期の方法を習得します。
以下の方に役立つ内容となっています。
- TextBoxなどの入力コントロールとデータを自動同期したい方
- TwoWayバインディングの仕組みを理解したい方
- WPFのデータバインディングを完全にマスターしたい方
TextBoxに入力された内容を自動的にデータオブジェクトに反映させるには、双方向バインディング(TwoWay)の設定が必要です。
この記事では、前回のサンプルを拡張し、社員情報の名前と職業をTextBoxで編集可能にするアプリを作成します。

前回の記事を先にご覧いただくと、データバインディングについてより理解が深まります。


前回学んだINotifyPropertyChangedを基盤として、今度は「UI→データ」の同期も実現していきましょう!
MVVMパターンでも頻繁に使う重要な機能です。
演習のコード一式はGitHubに置いてあります。
動画も作成しています。
講義:双方向バインディングの仕組み
前回の課題
前回作成したアプリでは、ボタンクリックによる年齢変更は正しくUIに反映されますが、逆にUI側から直接データを編集することはできませんでした。
// TextBlock(例:名前の表示)は表示専用なので、ユーザが編集できない
<TextBlock Text="{Binding Name, StringFormat='名前: {0}'}"/>

実際のアプリでは、ユーザがフォームに入力した内容をデータオブジェクトに反映させたいケースが多々あります。
双方向バインディングとは?
双方向バインディング(Two-Way Binding)は、以下の両方向の同期を自動的に行う仕組みです。
- データ→UI: プロパティ値の変更がUIに反映される(前回実装済み)
- UI→データ: UI入力の変更がプロパティ値に反映される(今回実装)
これにより、TextBoxに入力すると即座にデータオブジェクトのプロパティが更新され、他の画面部分にも変更が反映されるようになります。
双方向バインディングの実装方法
コントロールでバインディングのモードを「Mode=TwoWay」とすることで、双方向バインディングの指定を行えます。
多くのコントロールではデフォルトで適切なモードが設定されているため、明示的な指定は不要な場合もあります。
<!-- 双方向バインディングの基本形 -->
<TextBox Text="{Binding Name, Mode=TwoWay}"/>
<!-- TextBoxはデフォルトでTwoWayなので、以下でもOK -->
<TextBox Text="{Binding Name}"/>
双方向バインディングでは、いつデータを更新するかをUpdateSourceTriggerで制御できます。以下が例です。
<!-- フォーカスを失った時の更新 - パフォーマンス重視 -->
<TextBox Text="{Binding Name, UpdateSourceTrigger=LostFocus}"/>
<!-- 入力のたびに更新 - リアルタイム性重視 -->
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
UpdateSourceTriggerには以下を指定できます。
UpdateSourceTrigger | 説明 | 用途 |
---|---|---|
Default | コントロールのデフォルト動作 | 通常はこれを使用 |
PropertyChanged | プロパティ変更のたびに更新 | リアルタイム同期 |
LostFocus | フォーカスを失った時 | 入力完了後の更新 |
Explicit | 明示的な更新指示 | 手動制御 |
TextBoxでPropertyChangedを指定すると、1文字入力するたびにデータが更新されるため、リアルタイムな同期が実現できます。
Microsoft Learnの「Binding.UpdateSourceTrigger プロパティ」の記事も参考にしてください。
演習:TextBoxで名前と職業を編集可能にする
作成するアプリの概要
前回のアプリを拡張して、以下の機能を追加します。
- 名前・職業をTextBoxで編集可能にする
(双方向同期でデータを更新する) - 人物情報の現在の各値をテキストとして表示する
(双方向同期でデータが更新されていることがわかるようにする)
以下の手順で作成します。
- 手順: 入力フォーム(名前・仕事)と人物情報表示部分を追加
(XAML)
前回のINotifyPropertyChanged実装をそのまま活用して、双方向同期を実現します!
手順:入力フォーム(名前・仕事)と人物情報表示部分を追加
(XAML)
前回のプロジェクトのMainWindow.xamlを以下のように修正し、人物情報の「名前」、「仕事」のTextBlockをTextBoxに変更します。
加えて、人物情報のデータ表示部分も追加します。(★追加)とした箇所が新しく追加した部分です。
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel Margin="10">
<!-- タイトル -->
<TextBlock Text="データバインディング基礎デモ"
FontSize="16" FontWeight="Bold"
HorizontalAlignment="Center" Margin="0,0,0,15"/>
<!-- 人物情報エリア -->
<GroupBox Header="人物情報" Margin="0,0,0,10">
<StackPanel Margin="5">
<!-- 名前入力(★追加) -->
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<Label Content="名前:" Width="60"/>
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
Width="200" Height="25"/>
</StackPanel>
<!-- 年齢操作 -->
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<TextBlock Text="{Binding Age, StringFormat='年齢: {0}'}"/>
<Button Content="-" Width="20" Height="20" Margin="10,0,5,0" Click="OnDecrementAge"/>
<Button Content="+" Width="20" Height="20" Margin="5,0,0,0" Click="OnIncrementAge"/>
</StackPanel>
<!-- 職業入力 (★追加)-->
<StackPanel Orientation="Horizontal">
<Label Content="職業:" Width="60"/>
<TextBox Text="{Binding Job, UpdateSourceTrigger=PropertyChanged}"
Width="200" Height="25"/>
</StackPanel>
</StackPanel>
</GroupBox>
<!--人物情報の現在のデータを確認するためのエリア(★追加) -->
<GroupBox Header="人物情報(現在のデータを表示)" Margin="0,0,0,15">
<StackPanel Margin="10">
<TextBlock Text="{Binding Name, StringFormat=名前: {0}}" />
<TextBlock Text="{Binding Age, StringFormat=年齢: {0}歳}" />
<TextBlock Text="{Binding Job, StringFormat=職業: {0}}" />
</StackPanel>
</GroupBox>
<!-- 会社情報エリア -->
<GroupBox x:Name="CompanyGroup" Header="会社情報">
<StackPanel Margin="5">
<TextBlock Text="{Binding Name, StringFormat='会社名: {0}'}"/>
<TextBlock Text="{Binding Department, StringFormat='部署: {0}'}"/>
</StackPanel>
</GroupBox>
</StackPanel>
</Window>
このXAMLの変更だけで完成です!
今回、C#コードビハインドに修正は必要ないの?
前回、INotifyPropertyChangedインターフェイスを実装し、Personについてはすでに双方向同期が可能になっているため、今回修正は不要です。
アプリを実行
アプリをデバッグ実行して、名前や仕事をテキストボックスから変更してみましょう。

TextBoxに入力すると、下の表示エリアが即座に変わる!これが双方向バインディングの効果だね。
INotifyPropertyChangedインターフェイスを一度実装しておけば、各プロパティのデータバインディングは比較的簡単ですね。
UpdateSourceTriggerをLostFocusに変更するなど、色々試してみると理解が深まると思います。
まとめ
本記事では、WPF開発における双方向データバインディングの実装について学びました。
前回学んだ「データ→UI」の単方向同期に加えて、今回は「UI→データ」も含めた双方向同期を実装しました。
名前・職業編集アプリの演習を通じて、前回実装したINotifyPropertyChangedインターフェイスを活用した双方向同期の方法を学びました。
UpdateSourceTrigger=PropertyChangedを指定することで、1文字入力するたびにデータが更新される双方向バインディングを実現できます。
UIからの入力をリアルタイムでデータに反映し、同時に他の画面要素にも即座に表示するというような機能は、実用的なWPFアプリ開発において欠かせない要素となります。
次回はコマンドの解説をします。データバインディングとあわせて、MVVMパターンの基礎となる2本柱の1つです。
引き続き、一緒にC# WPFアプリ開発を学んでいきましょう!