質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

5840閲覧

WPFでTabControl内へ子画面を表示させる方法

退会済みユーザー

退会済みユーザー

総合スコア0

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

0クリップ

投稿2020/12/13 08:19

実現したいこと

・ボタンクリックで動的に作成したタブの中に、別に作成した子画面の内容を表示させたい。
ToDoボタンをクリックしたときに、動的にタブを追加しています。
追加されたタブの中に自作のカレンダー画面を表示させたいと思っているのですが。
画面をタブの中に埋め込むような形で表示させることを可能ですか?

・TabControlの表示/非表示を切り替えたい
起動時は指定した画像を表示させるようにしている(TabControlを非表示に設定)のですが、ToDoボタンがクリックされたときは画像を非表示に、TabControlを表示させたいと考えています。
ToDoボタンはAddTabItemToDoCommandでBindingしているのですが、連動して別の処理を実行させるような方法はありますか?

  よろしくお願いいたします。

ソース

xml:MainWindow.xaml

1<Window x:Class="WpfApp.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:vm="clr-namespace:WpfApp.ViewModel" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 10 <Window.DataContext> 11 <vm:MainViewModel /> 12 </Window.DataContext> 13 14 <Grid> 15 <Grid.RowDefinitions> 16 <RowDefinition Height="Auto" /> 17 <RowDefinition /> 18 <RowDefinition Height="AUto"/> 19 </Grid.RowDefinitions> 20 <Grid.ColumnDefinitions> 21 <ColumnDefinition Width="2*"/> 22 <ColumnDefinition Width="8*"/> 23 </Grid.ColumnDefinitions> 24 25 <GroupBox Grid.Row="1" Grid.Column="0" 26 Margin="1" Background="Papayawhip"> 27 <StackPanel> 28 <Button Command="{Binding AddTabItemToDoCommand}" Style="{StaticResource FlatButton}"> 29 <!-- ボタンの中に表示する内容 --> 30 <TextBlock Text="ToDo" HorizontalAlignment="Center" VerticalAlignment="Center"/> 31 </Button> 32 </StackPanel> 33 </GroupBox> 34 35 <Image Source="{Binding BackgroundImage}" Stretch="Uniform" Grid.Row="1" Grid.Column="1"/> 36 <TabControl x:Name="tabControl" ItemsSource="{Binding TabItems}" Grid.Row="1" Grid.Column="1" > 37 <TabControl.ItemTemplate> 38 <!--ヘッダテンプレート--> 39 <DataTemplate> 40 <TextBlock Text="{Binding TabHeader}" /> 41 </DataTemplate> 42 </TabControl.ItemTemplate> 43 44 <TabControl.ContentTemplate> 45 <!--TabItemのコンテンツ--> 46 <DataTemplate> 47 <TextBlock Text="{Binding TabContent}" /> 48 </DataTemplate> 49 </TabControl.ContentTemplate> 50 </TabControl> 51 52 53 <!--ステータスバー--> 54 <TextBlock x:Name="StatusBar_Text" Grid.Row="2" HorizontalAlignment="Right"/> 55 56 </Grid> 57</Window>

c#:ViewModel

1namespace WpfApp.ViewModel 2{ 3 public class MainViewModel : BindableBase 4 { 5    private ImageSource _backgroundImage = null; 6 7 /// <summary> 8 /// メイン画面の背景 9 /// </summary> 10 public ImageSource BackgroundImage 11 { 12 get { return this._backgroundImage; } 13 set 14 { 15 this.SetProperty(ref this._backgroundImage, value); 16 } 17 } 18 19 /// <summary> 20 /// TabItemカレンダー画面追加コマンド 21 /// </summary> 22 public DelegateCommand AddTabItemToDoCommand{ get; } 23 24 /// <summary> 25 /// TabItemデータコレクション 26 /// </summary> 27 public ObservableCollection<TabItemData> TabItems { get; set; } = new ObservableCollection<TabItemData>(); 28 29 public MainViewModel() 30 { 31       // Main画面の画像の表示 32 BackgroundImage = new BitmapImage(new Uri("pack://application:,,,/Resources/BackgroundImage.jpg")); 33 34 this.AddTabItemToDoCommand= new DelegateCommand(() => 35 { 36 this.TabItems.Add(new TabItemData() { TabHeader = "ToDo", TabContent = "カレンダー的のものを表示させる予定" }); 37 }, () => string.IsNullOrEmpty(null)); 38 } 39 } 40 41 /// <summary> 42 /// TabItemを管理 43 /// </summary> 44 public class TabItemData 45 { 46 public string TabHeader { get; set; } 47 48 public string TabContent { get; set; } 49 } 50}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ボタンクリックで動的に作成したタブの中に、別に作成した子画面の内容を表示させたい。

方法はいろいろあります。私ならこうするかな?という案です。
それぞれ独立性の高い子画面なら、DataTemplateでビューを切り替えるのがいいと思います。

TabControlの表示/非表示を切り替えたい

まあどちらでもいいんですが、ImageVisibilityboolで切り替えてみました。

xml

1<Window 2 x:Class="Questions309980.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Questions309980" 6 Title="MainWindow" 7 Width="800" 8 Height="450"> 9 <Window.DataContext> 10 <local:MainViewModel /> 11 </Window.DataContext> 12 <Window.Resources> 13 <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> 14 <Style TargetType="{x:Type Button}"> 15 <Setter Property="Margin" Value="5" /> 16 <Setter Property="MinWidth" Value="80" /> 17 </Style> 18 19 <!-- DataTemplateでタブのコンテントを切り替える --> 20 <!-- UserControlを作ってもいいし --> 21 <DataTemplate DataType="{x:Type local:ToDoViewModel}"> 22 <local:ToDoView /> 23 </DataTemplate> 24 25 <!-- 簡単な内容ならこの場で作ってもいい --> 26 <DataTemplate DataType="{x:Type local:CalendarViewModel}"> 27 <DockPanel> 28 <TextBlock 29 DockPanel.Dock="Top" 30 FontSize="24" 31 FontWeight="Bold" 32 Text="Calendar" /> 33 <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> 34 <Button Command="{Binding HogeCommand}" Content="Hoge" /> 35 </StackPanel> 36 <Calendar HorizontalAlignment="Left" VerticalAlignment="Top" SelectedDate="{Binding SelectedDate}" /> 37 </DockPanel> 38 </DataTemplate> 39 </Window.Resources> 40 41 <DockPanel> 42 <TextBlock Text="{Binding StatusMessage}" HorizontalAlignment="Right" DockPanel.Dock="Bottom" /> 43 44 <GroupBox Background="Papayawhip"> 45 <StackPanel> 46 <Button Command="{Binding Command}" CommandParameter="{x:Type local:ToDoViewModel}" Content="ToDo" /> 47 <Button Command="{Binding Command}" CommandParameter="{x:Type local:CalendarViewModel}" Content="Calendar" /> 48 </StackPanel> 49 </GroupBox> 50 51 <Grid> 52 <TabControl ItemsSource="{Binding TabItems}" SelectedItem="{Binding SelectedItem}"> 53 <TabControl.ItemTemplate> 54 <DataTemplate> 55 <TextBlock Text="{Binding TabHeader}" /> 56 </DataTemplate> 57 </TabControl.ItemTemplate> 58 </TabControl> 59 60 <!-- はじめは上に重なってTabControlを隠している --> 61 <Image 62 HorizontalAlignment="Left" 63 VerticalAlignment="Top" 64 Source="https://teratail-v2.storage.googleapis.com/uploads/avatars/u13/132786/KnkDDC5A_thumbnail.jpg" 65 Visibility="{Binding IsImageVisible, Converter={StaticResource BooleanToVisibilityConverter}}" /> 66 </Grid> 67 </DockPanel> 68</Window>

xml

1<UserControl 2 x:Class="Questions309980.ToDoView" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 6 xmlns:local="clr-namespace:Questions309980" 7 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 8 d:DesignHeight="450" 9 d:DesignWidth="800" 10 mc:Ignorable="d"> 11 <DockPanel> 12 <TextBlock 13 DockPanel.Dock="Top" 14 FontSize="24" 15 FontWeight="Bold" 16 Text="ToDo" /> 17 <StackPanel DockPanel.Dock="Top" Orientation="Horizontal"> 18 <Button Command="{Binding AddCommand}" Content="Add" /> 19 <Button Command="{Binding DelCommand}" Content="Del" /> 20 <Button Command="{Binding DoneCommand}" Content="Done" /> 21 </StackPanel> 22 <ListBox> 23 <ListBoxItem Content="aaa" /> 24 <ListBoxItem Content="bbb" /> 25 <ListBoxItem Content="ccc" /> 26 </ListBox> 27 </DockPanel> 28</UserControl>

cs

1using Prism.Commands; 2using Prism.Mvvm; 3using System; 4using System.Collections.ObjectModel; 5using System.Diagnostics; 6using System.Linq; 7 8namespace Questions309980 9{ 10 public class MainViewModel : BindableBase 11 { 12 private bool _IsImageVisible = true; 13 public bool IsImageVisible { get => _IsImageVisible; set => SetProperty(ref _IsImageVisible, value); } 14 15 private TabItemBase _SelectedItem; 16 public TabItemBase SelectedItem { get => _SelectedItem; set => SetProperty(ref _SelectedItem, value); } 17 18 private string _StatusMessage; 19 public string StatusMessage { get => _StatusMessage; set => SetProperty(ref _StatusMessage, value); } 20 21 public ObservableCollection<TabItemBase> TabItems { get; } = new(); 22 23 public DelegateCommand<Type> Command { get; } 24 25 26 public MainViewModel() 27 { 28 Command = new(type => 29 { 30 // ImageのVisibilityを切り替える 31 IsImageVisible = false; 32 33 // switch文等で作り分けてもいいが、面倒なので型(Type)から直で生成 34 var item = (TabItemBase)Activator.CreateInstance(type); 35 36 // item追加 37 TabItems.Add(item); 38 39 // item選択 40 SelectedItem = item; 41 42 // CanExecuteを再確認させる 43 Command.RaiseCanExecuteChanged(); 44 45 StatusMessage = $"{type.Name} 読み込み"; 46 }, 47 // 同じボタンは2回押せないようにする(TabItemsにすでに同じ型があるかどうか) 48 type => !TabItems.Any(x => x.GetType().Equals(type))); 49 } 50 } 51 52 public abstract class TabItemBase : BindableBase 53 { 54 public string TabHeader { get; } 55 public TabItemBase(string header) => TabHeader = header; 56 } 57 58 public class ToDoViewModel : TabItemBase 59 { 60 public DelegateCommand AddCommand { get; } 61 public DelegateCommand DelCommand { get; } 62 public DelegateCommand DoneCommand { get; } 63 64 65 public ToDoViewModel() : base("ToDo") 66 { 67 AddCommand = new(() => Debug.WriteLine("AddCommand")); 68 DelCommand = new(() => Debug.WriteLine("DelCommand")); 69 DoneCommand = new(() => Debug.WriteLine("DoneCommand")); 70 } 71 } 72 73 public class CalendarViewModel : TabItemBase 74 { 75 private DateTime _SelectedDate; 76 public DateTime SelectedDate { get => _SelectedDate; set => SetProperty(ref _SelectedDate, value); } 77 78 public DelegateCommand HogeCommand { get; } 79 80 81 public CalendarViewModel() : base("Calendar") => HogeCommand = new(() => Debug.WriteLine(SelectedDate)); 82 } 83}

BindableBaseDelegateCommandは、Prism.Coreを使用しました。
NuGet Gallery | Prism.Core 8.0.0.1909

特に指定がないので.NET 5.0で書きました^^
.NET Framework 4.8等では、new()でエラーが出るので型を書いてください。

Target-typed new expressions - C# 9.0 specification proposals | Microsoft Docs
ターゲットからの new 型推論 | ++C++; // 未確認飛行 C
アプリ画像


[Q&A] WPF MVVMの学習 - Qiita

teratailでは、マルチポスト※の推奨はしていません。

ヘルプ|teratail(テラテイル)
上記確認の上、適切に対応してください。

投稿2020/12/13 15:39

編集2023/07/25 13:57
TN8001

総合スコア9862

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/12/15 11:55 編集

回答ありがとうございます。 教えていただいた内容で当方の環境でも動かすことができました。 Viewに関してなのですが、ある程度固定的な枠の場合はDockPanelを使用するという認識でよろしいでしょうか? >teratailでは、マルチポスト※の推奨はしていません。 申し訳ありません。内容を把握していませんでした。 別サイトの質問は取り下げました。
TN8001

2020/12/15 11:58

>DockPanelを使用するという認識でよろしいでしょうか? Grid.Row="1"等の数字をレイアウト変更時に書き換えるのが面倒なので、最近はDockPanelが好きですね。特に田の字で切るのは避けています。 まあこの辺は好みですしすべて置き換えれるものでもないので、面倒に感じないのであれば好きにされていいと思います^^ >別サイトの質問は取り下げました。 推奨しないだけで禁止というわけではないので、相互に状況を書いていただければいいのです。 先方にも解決した旨書いていただけたらと思います。
退会済みユーザー

退会済みユーザー

2020/12/17 05:27

ありがとうございます。 確かにGridのレイアウト変更の際は面倒になりそうですね。自分は慣れていないので、指定する数字などもよく間違えてしまいます。 もっと色んなものを作成していく中で、使い分けできるようにしていこうと思います。 回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問