2009-07-14 2 views
3

listview에서 상황에 맞는 메뉴를 사용하여 해당 항목의 원래 데이터가 필요한 코드를 실행하려고합니다.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 question과이 MSDN 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에서이 작업을 수행하는 대신 codebehind에서 바인딩을 설정해야합니다.당신은뿐만 아니라 비록 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

클릭 핸들러가 위치한 코드 숨김 파일에서 lvResources에 액세스 할 수 있기 때문에 cmMetadata_Click 핸들러에서 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

클릭 한 내용을 확인하기 위해 listview 선택 만 사용하는 것에 대해 언급하고자합니다. 사용자가 여러 항목을 선택했지만 클릭 한 항목에 대해 코드를 실행하려는 경우에는 제대로 작동하지 않습니다.이 경우 검색 할 수 없습니다. – patjbs

+0

+1 그것은 나를 많이 도왔습니다. –

2

Charlie의 답변과 유사하지만 XAML 변경이 필요하지 않습니다.

private void cmMetadata_Click(object sender, RoutedEventArgs e) 
{ 
    MenuItem menu = sender as MenuItem; 
    ListViewItem lvi = lvResources.ItemContainerGenerator.ContainerFromItem(menu.DataContext) as ListViewItem; 
} 
관련 문제