dataContext をグリッドにバインドしようとしていました (以下の xaml)
<Grid .... DataContext="{Binding Path=NewFormViewModel}" > ...</Grid>
このバインディングは機能せず、NewFormViewModel のゲッターが呼び出されていないことに気付きました。
この時点で、グリッドは xaml ファイルのルート要素でした。
次に、グリッド内にキャンバスを配置し、次のようにキャンバスにバインドしました。
<Grid ....>
<Canvas DataContext="{Binding Path=NewFormViewModel}">
....
</Canvas>
</Grid>
データバインディングは機能しました。
次に、グリッドをキャンバスに変更して、次のようにデータバインディングを試みました。
<Canvas.... DataContext="{Binding Path=NewFormViewModel}" > ...</Canvas>
バインディングが再び機能しなくなりました。
最終的に、キャンバス内にネストされたグリッドに落ち着きました。
<Canvas....>
<Grid DataContext="{Binding Path=NewFormViewModel}">
....
</Grid>
</Canvas>
問題は、xaml のルート要素へのバインドが機能しなかったのはなぜですか?
または、Canvas/Grid をルート要素としてまったく使用せず、Page/UserControl などを使用するべきでしたか?
編集
私の論理ツリーは次のようになります。
Window <- Data binding to object o
|
*
Frame <-Data binding to obect o inherited
|
*
Canvas/Grid <- Data binding to o.NewFormViewModel failed
|
*
Canvas/Grid <- Data binding to o.NewFormViewModel Succeeds
EDIT2:
壊れた xaml:
<Canvas x:Class="WPFEditors.NewForm"
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"
mc:Ignorable="d" Height="398" Width="377"
DataContext="{Binding Path=NewFormViewModel}"
>
<Grid >
<Label DataContext="Form Type" Height="31" HorizontalAlignment="Left" Margin="12,22,0,0" VerticalAlignment="Top" Width="92" />
<ComboBox Margin="148,22,6,347" ItemsSource="{Binding Path=FormTypes}" />
<Label Content="Description" Height="31" HorizontalAlignment="Left" Margin="12,58,0,0" VerticalAlignment="Top" Width="92" />
<Label Content="{Binding Path=Heading}" ToolTip="This is pulled from the Enum defined for FormTypes" Margin="148,59,6,309" />
<Label Content="Version" Height="31" HorizontalAlignment="Left" Margin="12,95,0,0" VerticalAlignment="Top" Width="92" />
<TextBox Text="Bind this later" Margin="148,97,6,270" Height="31" />
<Label Content="Approval Level" Height="31" HorizontalAlignment="Left" Margin="12,132,0,0" VerticalAlignment="Top" Width="92" />
<TextBox Height="31" Margin="148,134,6,233" Text="Bind this later" />
<Label Content="Number of Approvals" Height="31" HorizontalAlignment="Left" Margin="12,171,0,0" VerticalAlignment="Top" Width="130" />
<TextBox Height="31" Margin="148,173,6,194" Text="Bind this later" />
<Label Content="Heading" Height="31" HorizontalAlignment="Left" Margin="12,210,0,0" VerticalAlignment="Top" Width="130" />
<TextBox Height="31" Margin="148,212,6,155" Text="Bind this later" />
<Label Content="Static Data Id" Height="31" HorizontalAlignment="Left" Margin="12,247,0,0" VerticalAlignment="Top" Width="130" />
<TextBox Height="31" Margin="148,249,6,118" Text="Bind this later" />
<Label Content="{Binding Path=Errors}" Background="{Binding Path=Color}" Margin="12,325,6,6" BorderThickness="1" BorderBrush="#FF000019" />
<Button Content="Create" Margin="83,294,202,78" />
<Button Content="Create" Margin="181,294,104,78" />
<Button Content="Create" Margin="279,294,6,78" />
</Grid>
</Canvas>
上記の xaml では、次の行がバインドされます。
<Label Content="{Binding Path=Heading}"
見出しは、このドキュメントが継承するビューモデルのプロパティ内にありますが。この時点で、次の行を期待していました。
DataContext="{Binding Path=NewFormViewModel}"
datacontext を見出しのない NewFormViewModel に変更しました。残りのバインディングはすべて失敗します。
先頭を次のように変更すると:
<Canvas x:Class="NewForm"
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"
mc:Ignorable="d" Height="398" Width="377"
>
<Grid DataContext="{Binding Path=NewFormViewModel}" >
見出しへのバインディングが失敗し、残りのバインディングが機能し始めます。これは、私が最初に期待していた動作です。
この xaml は、次のファイルにネストされています。
<Window x:Class="WPFEditors.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{Binding Path=Heading}" Height="743" Width="1177">
<StackPanel >
<Menu IsMainMenu="True" >
<MenuItem Header="New">
<MenuItem Header="New Form" Command="{Binding Path=MenuCommand}" />
</MenuItem>
<MenuItem Header="Edit Form" ItemsSource="{Binding Path=FormsAvailable}" />
<MenuItem Header="Edit Rules" />
</Menu>
<Frame NavigationUIVisibility="Hidden" Source="{Binding Path=CurrentPage}"
LoadCompleted="Frame_LoadCompleted"
DataContextChanged="Frame_DataContextChanged"
Name="frame">
</Frame>
</StackPanel>
</Window>
データ コンテキストを子にコピーするイベント ハンドラは次のとおりです。
private void Frame_LoadCompleted(object sender, NavigationEventArgs e)
{
UpdateFrameDataContext();
}
private void Frame_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
UpdateFrameDataContext();
}
private void UpdateFrameDataContext()
{
var content = frame.Content as FrameworkElement;
if (content == null)
return;
content.DataContext = frame.DataContext;
}