2009-05-07 6 views
3

リスト内の項目にはコンテキストメニューがあります。コンテキストメニュー項目は、ルーティングされたコマンドにバインドされています。WPF - ContextMenuアイテムはListBoxでは動作しますが、ItemsControlでは動作しないのはなぜですか?

リストコントロールがListBoxの場合、コンテキストメニュー項目は正しく機能しますが、それをItemsControlにダウングレードするとすぐに機能しなくなります。具体的には、メニュー項目は常にグレー表示されます。私のCommandBindingCanExecuteコールバックも呼び出されていません。

それはコマンドでコンテキストメニュー項目が正常にバインドすることを可能にすることについてListBoxは何ですか?ここで

は、私は問題を強調するために一緒に入れたサンプルアプリからいくつか抜粋されています

<!-- Data template for items --> 
<DataTemplate DataType="{x:Type local:Widget}"> 
    <StackPanel Orientation="Horizontal"> 
    <StackPanel.ContextMenu> 
     <ContextMenu> 
     <MenuItem Header="UseWidget" 
        Command="{x:Static l:WidgetListControl.UseWidgetCommand}" 
        CommandParameter="{Binding}" /> 
     </ContextMenu> 
    </StackPanel.ContextMenu> 
    <TextBlock Text="{Binding Path=Name}" /> 
    <TextBlock Text="{Binding Path=Price}" /> 
    </StackPanel> 
</DataTemplate> 

<!-- Binding --> 
<UserControl.CommandBindings> 
    <CommandBinding Command="{x:Static l:WidgetListControl.UseWidgetCommand}" 
        Executed="OnUseWidgetExecuted" 
        CanExecute="CanUseWidgetExecute" /> 
</UserControl.CommandBindings> 

<!-- ItemsControl doesn't work... --> 
<ItemsControl ItemsSource="{Binding Path=Widgets}" /> 

<!-- But change it to ListBox, and it works! --> 
<ListBox ItemsSource="{Binding Path=Widgets}" /> 

は、ここでビューモデルとデータ項目のためのC#コードです:

public sealed class WidgetListViewModel 
{ 
    public ObservableCollection<Widget> Widgets { get; private set; } 

    public WidgetViewModel() 
    { 
     Widgets = new ObservableCollection<Widget> 
      { 
       new Widget { Name = "Flopple", Price = 1.234 }, 
       new Widget { Name = "Fudge", Price = 4.321 } 
      }; 
    } 
} 

public sealed class Widget 
{ 
    public string Name { get; set; } 
    public double Price { get; set; } 
} 

ここではC#のコードですコントロールの後ろに:

public partial class WidgetListControl 
{ 
    public static readonly ICommand UseWidgetCommand 
     = new RoutedCommand("UseWidget", typeof(WidgetListWindow)); 

    public WidgetListControl() 
    { 
     InitializeComponent(); 
    } 

    private void OnUseWidgetExecuted(object s, ExecutedRoutedEventArgs e) 
    { 
     var widget = (Widget)e.Parameter; 
     MessageBox.Show("Widget used: " + widget.Name); 
    } 

    private void CanUseWidgetExecute(object s, CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = true; 
     e.Handled = true; 
    } 
} 

ちょっと質問を繰り返してくださいListBoxは、コンテキストメニュー項目のコマンドを正しくバインドできるようにしています。ItemsControlの場合、これを実行できる方法はありますか?

+0

ItemsControlを使用している場合、ContextMenu内でCommandBindingsを直接定義すると機能しますが、これは最初のコマンドを使用する目的に反することに注意してください。私の推測では、これはListBoxItemオブジェクトの項目をラップするListBoxと関係があります... –

答えて

0

それはおそらくされたContextMenuポップアップ内の項目は、(基本的には、ポップアップが別のウィンドウで)ユーザーコントロールの残りの部分と同じビジュアルツリーをint型されていないという事実に関連します。そのためCommandBindingsは機能しません。

しかし、今、私はどのようにされたContextMenu内CommandBindingsをspecifingせずにこの問題を解決するアイデアを持っていないため。

+0

私はhttp://stackoverflow.com/questions/662164/wpf-context-menu-doesnt-bind-toでそれを読むでしょう-right-databound-itemしかし、ListBoxがまだ動作している理由については説明していません。ItemsControlはそうではありません。 ListBoxがコンテキストメニュー項目コマンドをバインド可能にするのは何ですか?私は.NET Reflectorで見たことがありますが、何も変えていません。 –

5

[OK]を、私が見る主な問題は、ItemsControlには、選択した項目の概念を持っていないということですので、あなたはにバインドするDataTemplateのためのアイテムを選択することはできません。私はそれを見たところ

は、私が覚えていないことができますが、WPFを書くことはあなたが必要振る舞いを与えるコントロールを使用し、それはあなたが望むものを見えるようにスタイルにあるときには良いルールが従うこと。

これを考えれば、ListBoxの動作が必要ですが、ItemsControlの外観なので、ListBoxItemsを選択したものと選択していないものの違いを表示しないようにスタイルを設定してください。

+0

ありがとうキャメロン、私はこのショットを今日与えるでしょう。私はまだItemsControlの項目が論理ツリーの一部であり、ルーティングされたイベントが正常に動くはずであると確信しているので、ListBoxが追加して、ルーティングされたコマンドをアイテムからトンネルできるようにしたいと思っています。 –

+0

ええと、私はReflectorがListBoxを特別なものにしたのを見つけようと、2時過ぎまで掘り下げていました。今朝、私はこれがより良い解決策になると考えました:P –

関連する問題