【WPF】1画面に複数のUserControlを可変で表示する方法
WPFで1つの画面の中に複数のUseControlを可変で表示させたいという要件があり、
以下のように実装することで実現することができました。
各クラスの役割
各クラスの役割はこんな感じです。 なお、いくつかのクラスは省略しています。詳細はサンプルコードを参考にしてください。
クラス名 | 役割 |
---|---|
DisplayControlViewModel.cs | 画面に表示させるUserControlのViewModelを抽象化したクラス |
ComboBoxControlViewModel.cs | DisplayControlViewmodelを継承したComboBoxControl.xaml のViewModel |
ComboBoxControl.xaml | ComboBoxを持ったUserControlクラス |
MainWindowViewModel.cs | MainWindow.xamlのViewModel |
MainWindow.xaml | 複数のUserControlを表示するWindow |
DisplayControlViewModel.cs
画面に表示させるUserControlに紐づくViewModelクラスを抽象化したクラスです。
namespace DisplayUserControlListSample.ViewModels { public abstract class DisplayControlViewModel { } }
ComboBoxControlViewModel.cs
ComboBoxControl.xamlのViewModelクラスです。DisplayControlViewModelを継承しています。
コンボボックスに表示されるItemのコレクションを持ち、コンストラクタで値を初期化しています。
using Reactive.Bindings; namespace DisplayUserControlListSample.ViewModels { public class ComboBoxControlViewModel : DisplayControlViewModel { /// <summary> /// コンボボックスに表示されるItemのコレクション /// </summary> public ReactiveCollection<string> Items { get; } public ComboBoxControlViewModel() { Items = new ReactiveCollection<string>() { "Apple", "Banana", "Peach" }; } } }
ComboBoxControl.xaml
1つのComboBoxのみをもつXAMLです。ItemsSourceにComboBoxControlViewModelからItemsをバインドしています。
<UserControl x:Class="DisplayUserControlListSample.Views.ComboBoxControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" Width="300" Height="30"> <Grid Margin="0,0,0,5" > <StackPanel Orientation="Horizontal"> <ComboBox Height="30" Width="300" FontFamily="MS Gothic" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" ItemsSource="{Binding Items}" > </ComboBox> </StackPanel> </Grid> </UserControl>
MainWindowViewModel.cs
DisplayControlViewModelクラスのコレクションをプロパティとしてもちます。このプロパティに表示したいUserControlに紐づいたViewModelのインスタンスを追加します。
※なお、本エントリーではTextBoxControlに関する説明は割愛しています
using Prism.Mvvm; using Reactive.Bindings; namespace DisplayUserControlListSample.ViewModels { public class MainWindowViewModel : BindableBase { public ReactiveCollection<DisplayControlViewModel> DisplayControlViewModels { get; } = new ReactiveCollection<DisplayControlViewModel>(); public MainWindowViewModel() { DisplayControlViewModels.Clear(); DisplayControlViewModels.Add(new ComboBoxControlViewModel()); DisplayControlViewModels.Add(new TextBoxControlViewModel()); DisplayControlViewModels.Add(new ComboBoxControlViewModel()); } } }
MainWindow.xaml
ItemsControl要素のItemsSourceプロパティにDisplayControlViewModelのリストをバインドします。
WindowのリソースにDataTemplateで表示するUserControlを定義します。
ItemsSourceにバインドされたDisplayControlViewModelのTypeを見て表示するUserControlを切り替えます。
<Window x:Class="DisplayUserControlListSample.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:views="clr-namespace:DisplayUserControlListSample.Views" xmlns:viewModels="clr-namespace:DisplayUserControlListSample.ViewModels" xmlns:prism="http://prismlibrary.com/" prism:ViewModelLocator.AutoWireViewModel="True" Height="350" Width="525" Title="DisplayUserControlListSample" Background="LightSlateGray"> <Window.Resources> <DataTemplate DataType="{x:Type viewModels:TextBoxControlViewModel}"> <views:TextBoxControl/> </DataTemplate> <DataTemplate DataType="{x:Type viewModels:ComboBoxControlViewModel}"> <views:ComboBoxControl/> </DataTemplate> </Window.Resources> <Grid> <ScrollViewer Margin="50,50,50,50" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" IsTabStop="False"> <ItemsControl ItemsSource="{Binding DisplayControlViewModels}" VerticalAlignment="Top" IsTabStop="False" /> </ScrollViewer> </Grid> </Window>
実行結果
実行結果はこのようになります。
MainWindowViewModel.csで追加したViewmodelに紐づくUserControlが表示されます。
サンプルコード
以下に公開しています。
https://github.com/Keenag/SampleCode/tree/master/DisplayUserControlListSample