wpf
WPFデータバインディングの概要
サーチ…
構文
- {Binding PropertyName} は {Binding Path = PropertyName}に相当します 。
- {バインディングパス= SomeProperty.SomeOtherProperty.YetAnotherProperty}
- {バインディングパス= SomeListProperty [1]}
パラメーター
パラメータ | 詳細 |
---|---|
パス | バインドするパスを指定します。指定されていない場合は、DataContext自体にバインドされます。 |
UpdateSourceTrigger | バインド元の値が更新される時期を指定します。デフォルトはLostFocus です。最もよく使用される値はPropertyChanged です。 |
モード | 通常OneWay またはTwoWay 。バインディングによって指定されていない場合は、バインディングターゲットがTwoWay ことを要求しない限り、デフォルトでOneWay になりTwoWay 。 TwoWay を使用して読み取り専用プロパティにバインドするときにエラーが発生します。たとえば、読み取り専用文字列プロパティをTextBox.Text にバインドするときにOneWay 明示的に設定する必要があります。 |
ソース | 現在のDataContextの代わりにStaticResource をバインディングソースとして使用できるようにします。 |
RelativeSource | 現在のDataContextではなく、バインディングソースとして別のXAML要素を使用できます。 |
ElementName | 現在のDataContextの代わりに名前付きXAML要素をバインディングソースとして使用できるようにします。 |
FallbackValue | バインディングが失敗した場合、この値はバインディングターゲットに提供されます。 |
TargetNullValue | バインディング・ソース値がnull 場合、この値はバインディング・ターゲットに提供されます。 |
コンバータ | バインディングの値を変換するために使用するコンバータStaticResource を指定します。たとえば、ブール値をVisibility 列挙型アイテムに変換します。 |
ConverterParameter | コンバータに提供されるオプションのパラメータを指定します。この値は静的でなければならず、バインドすることはできません。 |
StringFormat | バインドされた値を表示するときに使用する書式文字列を指定します。 |
ディレイ | (WPF 4.5+)バインディングがViewModel 内のBindingSource を更新する遅延をmilliseconds で指定しmilliseconds 。これをMode=TwoWay にするには、 Mode=TwoWay およびUpdateSourceTrigger=PropertyChanged を使用する必要があります。 |
備考
UpdateSourceTrigger
既定では、WPFはコントロールがフォーカスを失ったときにバインディングソースを更新します。ただし、フォーカスを取得できるコントロールが1つしかない場合(例でよく見られるようなもの)、アップデートを動作させるにはUpdateSourceTrigger=PropertyChanged
を指定する必要があります。
すべてのキーストロークでバインディングソースを更新するのはコストがかかり、ライブデータの検証が望ましくない場合を除き、多くの双方向バインディングでPropertyChanged
をトリガーとして使用したい場合があります。
LostFocus
を使用すると残念なことに副作用があります:Enterを押してIsDefault
マークされたボタンを使用してフォームを送信しても、バインディングをバックアップするプロパティは更新されず、変更を効果的に元に戻します。幸いにも、 いくつかの回避策が存在します。
また、UWPとは異なり、WPF(4.5以降)にはバインディングにDelay
プロパティがあり、一部のTextBox
検証のように、ローカルのみまたは単純なマイナーインテリジェンス設定を持つバインディングには十分であることに注意してください。
ブール値を可視値に変換する
この例では、チェックボックスがIValueConverter
を使用してチェックされていない場合、赤いボックス(枠線)が非表示になっています。
注:以下の例で使用されるBooleanToVisibilityConverter
は、System.Windows.Controls名前空間にある組み込みの値コンバータです。
XAML:
<Window x:Class="StackOverflowDataBindingExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="VisibleIfTrueConverter" />
</Window.Resources>
<StackPanel>
<CheckBox x:Name="MyCheckBox"
IsChecked="True" />
<Border Background="Red" Width="20" Height="20"
Visibility="{Binding Path=IsChecked,ElementName=MyCheckBox, Converter={StaticResource VisibleIfTrueConverter}}" />
</StackPanel>
</Window>
DataContextの定義
WPFでバインディングを処理するには、 DataContextを定義する必要があります。 DataContextは、デフォルトでデータを取得する場所をバインディングに指示します。
<Window x:Class="StackOverflowDataBindingExample.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:StackOverflowDataBindingExample"
xmlns:vm="clr-namespace:StackOverflowDataBindingExample.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:HelloWorldViewModel />
</Window.DataContext>
...
</Window>
コードビハインドを使用してDataContextを設定することもできますが、XAML IntelliSenseは多少なりともかわいいことに注意してください。XAMLで厳密に型指定されたDataContextをIntelliSenseで設定して、バインディングに使用できるプロパティを提案する必要があります。
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new HelloWorldViewModel();
}
}
より柔軟な方法でDataContextを定義するのに役立つフレームワークがありますが( MVVM Lightにはコントロールの反転を使用するビューモデルロケータがあります)、このチュートリアルの目的ではクイックメソッドとダーティメソッドを使用します。
WPFのほとんどすべてのビジュアル要素に対してDataContextを定義できます。 DataContextは、明示的にオーバーライドされている場合を除いて、一般にビジュアルツリー内の祖先から継承されます(例:ContentPresenter内)。
INotifyPropertyChangedの実装
INotifyPropertyChanged
は、プロパティが変更されたことをユーザーインターフェイスまたは他のコンポーネントに知らせるために、ソース(つまりDataContext)をバインドする際に使用されるインターフェイスINotifyPropertyChanged
。 PropertyChanged
イベントが発生したことをWPFが自動的にUIを更新します。すべてのビューモデルが継承できる基本クラスにこのインタフェースを実装することが望ましいです。
C#6では、これで必要なのは次のとおりです。
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
これにより、 NotifyPropertyChanged
を2つの異なる方法で呼び出すことができます。
-
NotifyPropertyChanged()
。 CallerMemberNameという属性のおかげで、呼び出すセッターのイベントを発生させます。 -
NotifyPropertyChanged(nameof(SomeOtherProperty))
、これはSomeOtherPropertyのイベントを発生させます。
C#5.0を使用している.NET 4.5以上では、これを代わりに使用できます。
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged([CallerMemberName] string name = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
4.5より前の.NETのバージョンでは、プロパティ名を文字列定数または式を使用して解決する必要があります 。
注: INotifyPropertyChanged
を実装していない "普通の古いC#オブジェクト"(POCO)のプロパティにバインドし、バインディングが期待どおりに機能することを確認することは可能INotifyPropertyChanged
。これは.NETの隠し機能であり、おそらく避けなければなりません。特に、バインディングのMode
がOneTime
( ここを参照) OneTime
、メモリリークが発生します。
INotifyPropertyChangedを実装せずにバインディングを更新するのはなぜですか?
別の名前付き要素のプロパティにバインドする
名前付き要素のプロパティにバインドできますが、名前付き要素はスコープ内になければなりません。
<StackPanel>
<CheckBox x:Name="MyCheckBox" IsChecked="True" />
<TextBlock Text="{Binding IsChecked, ElementName=MyCheckBox}" />
</StackPanel>
祖先の財産に束縛する
RelativeSource
バインディングを使用すると、ビジュアルツリー内の祖先のプロパティにバインドできます。ビジュアルツリー内の、同じタイプの、または指定したタイプから派生した最も近い最も近いコントロールがバインディングのソースとして使用されます。
<Grid Background="Blue">
<Grid Background="Gray" Margin="10">
<Border Background="Red" Margin="20">
<StackPanel Background="White" Margin="20">
<Button Margin="10" Content="Button1" Background="{Binding Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}}" />
<Button Margin="10" Content="Button2" Background="{Binding Background, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type FrameworkElement}}}" />
</StackPanel>
</Border>
</Grid>
</Grid>
この例では、最も近いGrid
祖先が灰色の背景を持つため、 Button1は灰色の背景を持っています。 Button2は、白い背景を持っていStackPanel
。これは、 FrameworkElement
から派生した最も近い祖先が白いStackPanel
です。
マルチバインディングで複数の値をバインドする
MultiBindingでは、複数の値を同じプロパティにバインドできます。次の例では、複数の値がTextboxのTextプロパティにバインドされ、StringFormatプロパティを使用して書式設定されています。
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="User.Forename"/>
<Binding Path="User.Surname"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
StringFormat
ほかに、 IMultiValueConverter
使用して、Bindingsの値をMultiBindingのターゲットの1つの値に変換することもできます。
ただし、MultiBindingをネストすることはできません。