7

アプリにメニューがあります。階層データ テンプレートを使用して視覚化しています。

    <MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" >
        <MenuItem.ItemTemplate>                    
            <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
                                      ItemsSource="{Binding Path=ChildrenItems}">                        
                <MenuItem Header="{Binding Name}" Command="{Binding RunOperationCommand}" />
            </HierarchicalDataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>

メニューは本来のように見えますが、各メニュー項目のコマンドは起動されません! さらに、デバッガーで見られるように、制限されていません。 ICommand プロパティの get アクセサーが実行されたことはありません。なぜそうなるのですか?

いつものように完璧に動作します:

<Menu>
    <MenuItem Header="SomeHeader" Command="{Binding RunOperationCommand}"/>
<Menu>
4

3 に答える 3

7

質問の最初の例と2番目の例の違いは、2番目のコードスニペットでは、定義されMenuItem.Commandている親のデータコンテキストにバインドしていることです。RunOperationCommand一方、最初の例でHierarchicalDataTemplateは、メニュー項目である「ローカル」DataContextにバインドしています。適切なプロパティがないため、バインディングは失敗します。

いくつかのオプションがあります。

  • 1つは、すでに回答で行ったように、コマンドプロパティを使用してメニュー項目を拡張することです。
  • コマンドを含むデータコンテキストを持つビジュアルツリーの上の相対ソースにバインドします。たとえば、コマンドがウィンドウのDataContextにあると仮定します。

    <MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" >
        <MenuItem.ItemTemplate>                    
            <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
                                      ItemsSource="{Binding Path=ChildrenItems}">                        
                <MenuItem Header="{Binding Name}" 
                          Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.RunOperationCommand}" 
                />
            </HierarchicalDataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>


<Window.Resources>
     <coreView:CommandReference x:Key="RunOperationCommand"
                                Command="{Binding RunOperationCommand}" />
</Window.Resources>

    <MenuItem Header="Main menu" ItemsSource="{Binding ApplicationMenu}" >
        <MenuItem.ItemTemplate>                    
            <HierarchicalDataTemplate DataType="{x:Type tm:RMenuItem}" 
                                      ItemsSource="{Binding Path=ChildrenItems}">                        
                <MenuItem Header="{Binding Name}" 
                          Command="{StaticResource RunOperationCommand}" 
                />
            </HierarchicalDataTemplate>
        </MenuItem.ItemTemplate>
    </MenuItem>
于 2009-12-21T14:08:35.430 に答える
1

問題の一部の解決策を見つけたようです。メニュー項目ごとに特定のコマンドインスタンスを作成する必要があるように思われるため、コマンドはバインドされていません。主要な問題は、ほとんどすべてのメニュー項目が同じコマンドを実行し、コマンドパラメータの値のみが異なることです。だから私はそうすべきです:

サンプルmenuitemクラス:

public class RMyMenuItem
{
    public string Name { get; set; }

    public string InputGesture { get; set; }

    public ICommand ItemCommand
    { get; set; }

    public List<RMyMenuItem> ChildrenItems { get; set; }
}

ViewModelのプロパティ:

public ObservableCollection<RMyMenuItem> ApplicationMenu
{
    get
    {
        //RApplicationMainMenu menu = new RApplicationMainMenu(0);
        //return new ObservableCollection<RMenuItem>(menu.Items);
        return new ObservableCollection<RMyMenuItem>()
        {
        new RMyMenuItem()
            {
                Name = "item1",                    
                ItemCommand = new DelegateCommand((param) => RunOperationExecute(param)),
                ChildrenItems = new List<RMyMenuItem>()
                {
        new RMyMenuItem()
        {
            Name = "item2",
            ItemCommand = new DelegateCommand((param) => RunOperationExecute(param))
        }
                }
            }
    };
    }

そしてXAML:

    <Menu.ItemContainerStyle>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Header" Value="{Binding Name}" />
            <Setter Property="MenuItem.Command" Value="{Binding ItemCommand}"/>   
            <Setter Property="MenuItem.CommandParameter" Value="123"/>
            <Setter Property="ItemsSource" Value="{Binding ChildrenItems}" />                    
        </Style>
    </Menu.ItemContainerStyle>
}
于 2009-12-21T13:01:48.110 に答える
1

この問題を掘り続けます。DataTemplate は別の MenuItem 内に MenuItem を作成するため、 ItemsContainer Style を使用して他の方法を試しました。

<Menu Height="23" DockPanel.Dock="Top" ItemsSource="{Binding ApplicationMenu}" >
                <Menu.ItemContainerStyle>
                    <Style TargetType="{x:Type MenuItem}">
                        <Setter Property="Header" Value="{Binding Name}" />
                        <Setter Property="Command" Value="{Binding RunOperationCommand}"/>   
                        <Setter Property="CommandParameter" Value="123"/>
                        <Setter Property="ItemsSource" Value="{Binding ChildrenItems}" />
                    </Style>
                </Menu.ItemContainerStyle>
               <!--<MenuItem  />-->
</Menu>

ApplicationMenu はカスタム RMenuItem クラスの監視可能なコレクションであることを忘れていました。したがって、この方法も機能しますが、コマンドも機能しません!!! しかし、興味深い機能に気付きました-ItemContainerStyleで定義されたコマンドバインディングが機能します-ItemContainerStyleで定義されたコマンドバインディングが機能します!!! -((なぜそうなるのか???? しかし、それは私の目的ではありません - RoutedCommand を割り当てる機能を備えたコレクションに基づいてメニューを構築するメカニズムを作成したいと思います (menuitem のホットキーを持つため)。 MVVM アプローチを使用すると、状況が複雑になります。メニュー項目のコレクションは ViewModel レイヤーに存在しますが、RoutedCommands はビューの機能であり、ViewModel で単純な ICommands を使用しています。

于 2009-12-21T09:54:23.940 に答える