Windows データ バインディングの概要
このトピックでは、コントロール (またはその他の UI 要素) を 1 つの項目にバインドする方法、または Windows App SDK アプリ内の項目のコレクションに項目コントロールをバインドする方法について説明します。 さらに、項目のレンダリングを制御する方法、選択内容に基づいて詳細ビューを実装する方法、表示するデータを変換する方法を示します。 詳細については、「データ バインディングの詳細な情報 」を参照してください。
前提 条件
このトピックでは、基本的な Windows App SDK アプリを作成する方法を知っていることを前提としています。 最初の Windows App SDK アプリを作成する手順については、「初めての WinUI 3 (Windows App SDK) プロジェクトを作成する」を参照してください。
プロジェクトを作成する
新しい空のアプリ、パッケージ (デスクトップの WinUI 3) C# プロジェクトを作成します。 "クイック スタート" という名前を付けます。
1 つの項目へのバインド
すべてのバインディングは、バインディング ターゲットとバインディング ソースで構成されます。 通常、ターゲットはコントロールまたはその他の UI 要素のプロパティであり、ソースはクラス インスタンス (データ モデルまたはビュー モデル) のプロパティです。 この例では、コントロールを 1 つの項目にバインドする方法を示します。 ターゲットは、TextBlock
の Text
プロパティです。 ソースは、オーディオ録音を表す Recording
という名前の単純なクラスのインスタンスです。 まずクラスを見てみましょう。
新しいクラスをプロジェクトに追加し、クラスに Recording
名前を付けます。
namespace Quickstart
{
public class Recording
{
public string ArtistName { get; set; }
public string CompositionName { get; set; }
public DateTime ReleaseDateTime { get; set; }
public Recording()
{
ArtistName = "Wolfgang Amadeus Mozart";
CompositionName = "Andante in C for Piano";
ReleaseDateTime = new DateTime(1761, 1, 1);
}
public string OneLineSummary
{
get
{
return $"{CompositionName} by {ArtistName}, released: "
+ ReleaseDateTime.ToString("d");
}
}
}
public class RecordingViewModel
{
private Recording defaultRecording = new Recording();
public Recording DefaultRecording { get { return defaultRecording; } }
}
}
次に、マークアップのウィンドウを表すクラスからバインディング ソース クラスを公開します。 これを行うには、RecordingViewModel
型のプロパティを MainWindow.xaml.csに追加します。
namespace Quickstart
{
public sealed partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
ViewModel = new RecordingViewModel();
}
public RecordingViewModel ViewModel{ get; set; }
}
}
最後に、TextBlock
を ViewModel.DefaultRecording.OneLineSummary
プロパティにバインドします。
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<TextBlock Text="{x:Bind ViewModel.DefaultRecording.OneLineSummary}"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</Window>
結果を次に示します。
のバインド
項目のコレクションへのバインド
一般的なシナリオは、ビジネス オブジェクトのコレクションにバインドすることです。 C# では、ジェネリック INotifyPropertyChanged
実装する必要があります。 詳細については、「データ バインディングの詳細」を参照してください。
次の例では、ListView を Recording
オブジェクトのコレクションにバインドします。 まず、ビュー モデルにコレクションを追加します。 これらの新しいメンバーを RecordingViewModel
クラスに追加するだけです。
public class RecordingViewModel
{
...
private ObservableCollection<Recording> recordings = new ObservableCollection<Recording>();
public ObservableCollection<Recording> Recordings{ get{ return recordings; } }
public RecordingViewModel()
{
recordings.Add(new Recording(){ ArtistName = "Johann Sebastian Bach",
CompositionName = "Mass in B minor", ReleaseDateTime = new DateTime(1748, 7, 8) });
recordings.Add(new Recording(){ ArtistName = "Ludwig van Beethoven",
CompositionName = "Third Symphony", ReleaseDateTime = new DateTime(1805, 2, 11) });
recordings.Add(new Recording(){ ArtistName = "George Frideric Handel",
CompositionName = "Serse", ReleaseDateTime = new DateTime(1737, 12, 3) });
}
}
次に、ListView を ViewModel.Recordings
プロパティにバインドします。
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Window>
Recording
クラスのデータ テンプレートをまだ提供していないので、UI フレームワークで実行できる最善の方法は、ListView内の各項目に対して ToString を呼び出す方法です。 ToString
の既定の実装では、型名を返します。
これを解決するには、ToString をオーバーライドして OneLineSummary
の値を返すか、データ テンプレートを指定します。 データ テンプレート オプションは、より一般的なソリューションであり、柔軟性が高くなります。 データ テンプレートは、コンテンツ コントロールの ContentTemplate プロパティまたはアイテム コントロールの ItemTemplate プロパティを使用して指定します。 Recording
用のデータ テンプレートを、結果の図と共に設計する 2 つの方法を次に示します。
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<TextBlock Text="{x:Bind OneLineSummary}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView ItemsSource="{x:Bind ViewModel.Recordings}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
XAML 構文の詳細については、「XAMLを使用して UI を作成する」を参照してください。 コントロール レイアウトの詳細については、「XAMLを使用してレイアウトを定義する」を参照してください。
詳細ビューの追加
ListView アイテム内の Recording
オブジェクトのすべての詳細を表示することを選択できます。 しかし、それは多くのスペースを占有します。 代わりに、項目を識別するのに十分なデータだけをアイテムに表示し、ユーザーが選択を行うときに、選択した項目のすべての詳細を、詳細ビューと呼ばれる別の UI に表示できます。 この配置は、マスター/詳細ビュー、またはリスト/詳細ビューとも呼ばれます。
これについては 2 つの方法があります。 詳細ビューは、ListViewの SelectedItem プロパティにバインドできます。 または、CollectionViewSourceを使用できます。この場合、ListView
と詳細ビューの両方を CollectionViewSource
にバインドします (これにより、現在選択されている項目が自動的に処理されます)。 両方の手法を次に示します。両方とも同じ結果を得られます (図を参照)。
手記
ここまで、このトピックでは{x:Bind} マークアップ拡張
まず、SelectedItem 手法を示します。 C# アプリケーションの場合、必要な唯一の変更はマークアップです。
<Window x:Class="Quickstart.MainWindow" ... >
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView x:Name="recordingsListView" ItemsSource="{x:Bind ViewModel.Recordings}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Recording">
<StackPanel Orientation="Horizontal" Margin="6">
<SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
<StackPanel>
<TextBlock Text="{x:Bind CompositionName}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel DataContext="{Binding SelectedItem, ElementName=recordingsListView}"
Margin="0,24,0,0">
<TextBlock Text="{Binding ArtistName}"/>
<TextBlock Text="{Binding CompositionName}"/>
<TextBlock Text="{Binding ReleaseDateTime}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
CollectionViewSource 手法では、最初に最上位レベルの Grid
のリソースとして CollectionViewSource
を追加します。
<Grid.Resources>
<CollectionViewSource x:Name="RecordingsCollection" Source="{x:Bind ViewModel.Recordings}"/>
</Grid.Resources>
手記
WinUI の Window クラスには、Resources
プロパティがありません。 代わりに、最上位の Grid
(または StackPanel
などの他の親 UI 要素) 要素に CollectionViewSource
を追加できます。 Page
内で作業している場合は、CollectionViewSource
を Page.Resources
に追加できます。
次に、ListView (名前を付ける必要がなくなったもの) と詳細ビューのバインドを調整して、CollectionViewSourceを使用します。 詳細ビューを CollectionViewSource
に直接バインドすることで、コレクション自体にパスが見つからないバインド内の現在の項目にバインドすることを意味することに注意してください。 バインディングのパスとして CurrentItem
プロパティを指定する必要はありませんが、あいまいさがある場合は指定できます。
...
<ListView ItemsSource="{Binding Source={StaticResource RecordingsCollection}}">
...
<StackPanel DataContext="{Binding Source={StaticResource RecordingsCollection}}" ...>
...
各ケースで同じ結果を次に示します。
表示するデータ値の書式設定または変換
上記のレンダリングに問題があります。 ReleaseDateTime
プロパティは単なる日付ではなく、DateTimeです。 そのため、必要以上の精度で表示されています。 1 つの解決策は、ReleaseDateTime.ToString("d")
と同等のものを返す文字列プロパティを Recording
クラスに追加することです。 ReleaseDate
プロパティに名前を付けると、日付と時刻ではなく日付が返されることを示します。 「ReleaseDateAsString
」と名付けることにより、文字列が返されることをさらに示します。
より柔軟なソリューションは、値コンバーターと呼ばれるものを使用することです。 独自の値コンバーターを作成する方法の例を次に示します。 次のコードを Recording.cs のソース コード ファイルに追加します。
public class StringFormatter : Microsoft.UI.Xaml.Data.IValueConverter
{
// This converts the value object to the string to display.
// This will work with most simple types.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// Retrieve the format string and use it to format the value.
string formatString = parameter as string;
if (!string.IsNullOrEmpty(formatString))
{
return string.Format(formatString, value);
}
// If the format string is null or empty, simply
// call ToString() on the value.
return value.ToString();
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
StringFormatter
のインスタンスをリソースとして追加し、ReleaseDateTime
プロパティを表示する TextBlock
のバインドで使用できるようになりました。
<Grid.Resources>
...
<local:StringFormatter x:Key="StringFormatterValueConverter"/>
</Grid.Resources>
...
<TextBlock Text="{Binding ReleaseDateTime,
Converter={StaticResource StringFormatterValueConverter},
ConverterParameter=Released: \{0:d\}}"/>
...
前述のように、書式設定の柔軟性のために、マークアップを使用して、コンバーター パラメーターを使用してコンバーターに書式文字列を渡します。 このトピックに示すコード例では、C# 値コンバーターはそのパラメーターを使用します。
結果を次に示します。
カスタム書式設定 を使用して日付を表示する
関連コンテンツ
Windows developer