2009-07-14 9 views
3

リストビューでコンテキストメニューを使用して、元のアイテムのデータを必要とするコードを実行しようとしています。ContextMenu MenuItemの実行時にListViewでクリックされたListViewItemを特定する

私が最初にちょうどこれをしなかった:

XAML:

<ListView x:Name="lvResources" ScrollViewer.VerticalScrollBarVisibility="Visible"> 
     <ListView.Resources> 
     <ContextMenu x:Key="resourceContextMenu"> 
      <MenuItem Header="Get Metadata" Name="cmMetadata" Click="cmMetadata_Click" /> 
     </ContextMenu> 
     </ListView.Resources> 
     <ListView.ItemContainerStyle> 
      <Style TargetType="{x:Type ListViewItem}"> 
       <Setter Property="ContextMenu" Value="{StaticResource resourceContextMenu}" /> 
      </Style> 
     </ListView.ItemContainerStyle> 
... 

のC#:

private void cmMetadata_Click(object sender, RoutedEventArgs e) 
    { 
     // code that needs item data here 
    } 

しかし、私は元のリストビューアイテムがそのようにアクセスできないことがわかりました。

MouseDownイベントを傍受してクリックされたlistviewitemにプライベートフィールドを設定するなど、これを回避する方法についていくつかの方法を読んだことがありますが、それはちょっとハッキリしているようですそのような方法でデータを渡します。そして、WPFは簡単だと思いますよね?私はこれをSO questionMSDN forum questionと読んだことがありますが、私はまだこれらの記事のどちらも私の場合にはうまくいかないので、実際にこれを行う方法がわかりません。コンテキストメニューにクリックされたアイテムを渡すより良い方法はありますか?

ありがとうございます!

答えて

1

私はコマンドソリューションを試して実装しようと決めました。私はそれが今働いていることにかなり満足しています。

まず、私のコマンドを作成しました。また、そこ

public SortableListView() 
{ 
    CommandBindings.Add(new CommandBinding(CustomCommands.DisplayMetadata, DisplayMetadataExecuted, DisplayMetadataCanExecute)); 
} 

とイベントハンドラを追加しました:次は私のカスタムリストビューコントロールでは、私は、コンストラクタに結合する新しいコマンドを追加

public static class CustomCommands 
{ 
    public static RoutedCommand DisplayMetadata = new RoutedCommand(); 
} 

public void DisplayMetadataExecuted(object sender, ExecutedRoutedEventArgs e) 
{ 
    var nbSelectedItem = (MyItem)e.Parameter; 

    // do stuff with selected item 
} 

public void DisplayMetadataCanExecute(object sender, CanExecuteRoutedEventArgs e) 
{ 
    e.CanExecute = true; 
    e.Handled = true; 
} 

すでにスタイルセレクタを使用して、スタイルをlistviに動的に割り当てていましたewのアイテムではなく、xamlでこれを行う代わりに、コードビハインドでバインディングを設定する必要があります。あなたにもかかわらず、XAMLでそれを行うことができます:

public override Style SelectStyle(object item, DependencyObject container) 
{ 
    ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(container); 
    MyItem selectedItem = (MyItem)item; 
    Style s = new Style(); 

    var listMenuItems = new List<MenuItem>(); 
    var mi = new MenuItem(); 
    mi.Header= "Get Metadata"; 
    mi.Name= "cmMetadata"; 
    mi.Command = CustomCommands.DisplayMetadata; 
    mi.CommandParameter = selectedItem; 
    listMenuItems.Add(mi); 

    ContextMenu cm = new ContextMenu(); 
    cm.ItemsSource = listMenuItems; 

    // Global styles 
    s.Setters.Add(new Setter(Control.ContextMenuProperty, cm)); 

    // other style selection code 

    return s; 
} 

を私はマウスクリックでフィールドを設定し、そのようにクリックされたものをアクセスしようとしようとするよりもはるかに優れ、このソリューションの感触が好きです。

3

よく、cmMetadata_Clickハンドラで、lvResourcesはクリックハンドラが配置されているコードビハインドファイルからアクセスできるので、lvResources.SelectedItemプロパティを照会するだけです。エレガントではありませんが機能します。

もう少しエレガントにしたい場合は、ContextMenuの設定場所を変更することができます。あなたのListViewItemのために、これは何

<ListView x:Name="lvResources" ScrollViewer.VerticalScrollBarVisibility="Visible"> 
<ListView.Style> 
    <Style TargetType="ListView"> 
    <Setter Property="ItemContainerStyle"> 
    <Setter.Value> 
    <Style TargetType="{x:Type ListViewItem}"> 
     <Setter Property="Template"> 
     <Setter.Value> 
     <ControlTemplate TargetType="{x:Type ListViewItem}"> 
     <TextBlock Text="{TemplateBinding Content}"> 
      <TextBlock.ContextMenu> 
      <ContextMenu> 
      <MenuItem Header="Get Metadata" Name="cmMetadata" Click="cmMetadata_Click" 
      DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"/> 
      </ContextMenu> 
      </TextBlock.ContextMenu> 
     </TextBlock> 
     </ControlTemplate> 
     </Setter.Value> 
     </Setter> 
    </Style> 
    </Setter.Value> 
    </Setter> 
    </Style> 
</ListView.Style> 
<ListViewItem>One Item</ListViewItem> 
<ListViewItem>Another item</ListViewItem> 
</ListView> 

がプラグインされたテンプレートでは、その後、あなたはあなたのメニュー項目ののDataContextにのListViewItemを割り当てるために便利なTemplatedParentショートカットを使用することができます。たとえば、あなたはこのような何かを試みることができます。

は、今すぐあなたのコードビハインドのようになります。

private void cmMetadata_Click(object sender, RoutedEventArgs e) 
{ 
    MenuItem menu = sender as MenuItem; 
    ListViewItem item = menu.DataContext as ListViewItem; 
} 

明らかに欠点は、あなたが今のListViewItemのテンプレートを完了する必要がありますが、私はあなたがあなたのニーズに合うものを見つけることができると確信していかなり早く。

+0

+1すてきで簡単な解決策です。 – patjbs

+0

私は、単にリストビューの選択を使って何がクリックされたのかを判断することに言及しておきたいと思います。ユーザーが複数のアイテムを選択したが、クリックしたアイテムでコードを実行したいだけの場合は、それはうまくいきません。その場合は検出できません。 – patjbs

+0

+1それは私を大いに助けました。 –

2

チャーリーの回答に似ていますが、XAMLの変更は必要ありません。

private void cmMetadata_Click(object sender, RoutedEventArgs e) 
{ 
    MenuItem menu = sender as MenuItem; 
    ListViewItem lvi = lvResources.ItemContainerGenerator.ContainerFromItem(menu.DataContext) as ListViewItem; 
} 
関連する問題