ContentControl経由でViewを呼び出すとViewModelが変わっちゃうらしい
かつてこんな記事を書きました。
bignight.hatenablog.com
それには例外がありました。
ContentControl経由でViewを呼び出すとViewModelを共有してくれない😱
さあどうする?というわけで実験してみました。
(ちなみにContentControl経由で子コントロールを呼ぶ方法は以下の記事を参考にしてください。今回はDataTemplate経由で子コントロールを呼びます。)
bignight.hatenablog.com
簡単なコードです
Viewはこんな感じ
<Window x:Class="WpfApp1.Window1" 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="Window1" Height="450" Width="800"> <Window.Resources> <DataTemplate x:Key="originalTemplate"> <Border BorderBrush="Orange" BorderThickness="1"> <local:myControl/> </Border> </DataTemplate> <local:myControlViewModel x:Key="myControlViewModel"/> </Window.Resources> <StackPanel> <TextBlock Text="Content:windowViewModel"/> <!--ContentControl経由でViewを呼ぶ。ContentはwindowViewModelとする。--> <ContentControl Content="{StaticResource myControlViewModel}" ContentTemplate="{StaticResource originalTemplate}"/> <TextBlock Text="Content:None"/> <!--ContentControl経由でViewを呼ぶ。Contentは指定しない。--> <ContentControl ContentTemplate="{StaticResource originalTemplate}"/> <TextBlock Text="Content:Binding"/> <!--ContentControl経由でViewを呼ぶ。Contentは{Binding}とする。--> <ContentControl Content="{Binding}" ContentTemplate="{StaticResource originalTemplate}"/> <TextBlock Text="{Binding Text}"/> </StackPanel> </Window>
コードビハインドでViewModelを指定します。
public partial class Window1 : Window { public Window1() { InitializeComponent(); DataContext = new Window1ViewModel(); } }
メインのWindowのViewModelの中身
public class Window1ViewModel { public string Text { get; set; } = "これはWindow1ViewModel"; }
子コントロールはこんな感じ
TextBlockのTextにTextをバインドさせてみます。
<UserControl x:Class="WpfApp1.myControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" Name="mine"> <StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Binding:"/> <TextBlock Text="{Binding}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Binding Text:"/> <TextBlock Text="{Binding Text}"/> </StackPanel> </StackPanel> </UserControl>
子コントロールのViewModel(最初にStaticResourceで指定したやつ)
public class myControlViewModel { public string Text { get; set; } = "これはmyControlViewModel"; }
私の当初の予想では「"これはWindow1ViewModel";」が3回表示されると思ったんですが、結果は違いました。
実行結果はこんな感じ
オレンジの枠で囲んであるところが子コントロールです。
Content="{Binding}" と記述したときだけViewModelの共有が行われています。
どうやらContentControlのViewModelはContentに何を指定したかに依存するようですね。
ContentControlを継承したButtonなんかどうなるんだろう。
まだまだ知らないことが沢山あります。