MVVMアーキテクチャを使用してContextMenu階層が動的に入力されるシステムをセットアップしています。コマンドを除いて、すべてのバインディングは正しく機能します。私のビューは、ItemContainerStyleを指定するContextMenuです。
ContextMenuのItemContainerStyleは次のように設定されます。
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding Command, Mode=OneWay}"/>
<Setter Property="IsCheckable" Value="{Binding IsCheckable}"/>
<Setter Property="IsChecked" Value="{Binding IsChecked, Mode=TwoWay}"/>
<Setter Property="Header" Value="{Binding Label}"/>
<Setter Property="ItemsSource" Value="{Binding Children}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContextMenu.ItemContainerStyle>
これまでのところ、ItemTemplateはありません。これは、スタイルで必要なすべての機能を実行できたようです。
ViewModelは、ラップするモデルのインスタンスを使用して構築する必要があるため、ContextMenuのDataContextをViewModelに明示的に設定できないようです(コンパイラーは、パラメーターのないコンストラクターがないと文句を言います。文句は、型コンバーターがそれが実際に何を意味するのかはわかりませんが(問題を解決できる可能性があります)、使用することもできます。
私のViewModelの関連部分は次のとおりです。まず、バインド可能な次の2つの読み取り専用の公開メンバーから始めます。
public CommandBinding CommandBinding { get; private set; }
public RoutedCommand Command { get { return CommandBinding.Command as RoutedCommand; } }
CommandBindingとそのコマンドは、コンストラクターでインスタンス化されます。
CommandBinding = new CommandBinding(new RoutedCommand(), CommandBinding_Executed, CommandBinding_CanExecute);
その構造で参照されているメソッドは、モデルのメンバーを操作するだけで、次のように実装されます。
void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
if (ContextItem.Command != null) ContextItem.Command(ContextItem);
}
void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = ContextItem.IsEnabled;
if (ContextItem.ExecuteConditions != null) e.CanExecute = ContextItem.ExecuteConditions.GetInvocationList().Cast<ExecuteCondition>().All(s => s() == true);
}
Commandへのバインドが実際に機能すると、CanExecuteがfalseを返しているかのように、すべての項目が淡色表示されているように見えます。ただし、CanExecuteにブレークポイントを設定すると、その時点で実行が中断することはありません(ただし、これはレイアウトのスレッド化が原因である可能性があります)。e.CanExecuteを明示的にtrueに設定し、CommandBinding_CanExecuteの他の行をコメントアウトしても、項目は淡色表示されたままになります。XAMLでは、Path =の有無にかかわらず、CommandメンバーとCommandBindingメンバーの両方にバインドしようとしましたが、すべて同じ効果があります。バインディングモードをOneWayToSourceに設定すると、デバッガーはプロパティが読み取り専用であり、操作できないと適切に文句を言います(ViewModelにコマンドを提供させたいので、これは意図されたものです)。
他の例と関連する問題の解決策を読みました。MVVMパターンに従うものの場合、実装がどのように異なるかを判断できません。
どのソリューションでも、モデルをパラメーターとして使用してViewModelを構築する必要があることを主張する必要があります。また、C#コードを残さずに、ビューをすべてXAMLのままにしておくことをお勧めします。