2010-09-19 35 views
2

我有一個帶有不同類的項目的ListBox。 DataTemplates用於以適當的方式呈現這些對象。我想在這些類的DataTemplates中有不同的上下文菜單。帶有DataTemplate的ListBox Item上的ContextMenu

一切工作正常使用鼠標,但使用鍵盤我無法調出上下文菜單。

這可能是因爲鍵盤焦點不在DataTemplate的內容上,而是在ListBoxItem上。

如何獲取ListBoxItem引用內容的ContextMenu?

示例代碼:

<Window x:Class="WpfApplication8.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:my="clr-namespace:WpfApplication8" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.Resources> 
    <DataTemplate DataType="{x:Type my:Orange}"> 
     <TextBlock> 
      Orange 
      <TextBlock.ContextMenu> 
       <ContextMenu> 
        <MenuItem Header="Peel"/> 
       </ContextMenu> 
      </TextBlock.ContextMenu> 
     </TextBlock> 
    </DataTemplate> 
    <DataTemplate DataType="{x:Type my:Apple}"> 
     <TextBlock> 
      Apple 
      <TextBlock.ContextMenu> 
       <ContextMenu> 
        <MenuItem Header="Uncore"/> 
       </ContextMenu> 
      </TextBlock.ContextMenu> 
     </TextBlock> 
    </DataTemplate> 
</Window.Resources> 
<Grid> 
    <ListBox ItemsSource="{Binding Fruits}"/> 
</Grid> 
</Window> 


using System.Windows; 
using System.Collections.ObjectModel; 

namespace WpfApplication8 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      Fruits = new ObservableCollection<Fruit>(); 
      Fruits.Add(new Apple()); 
      Fruits.Add(new Apple()); 
      Fruits.Add(new Orange()); 
      this.DataContext = this; 
     } 

     public ObservableCollection<Fruit> Fruits { get; set; } 
    } 

    public class Fruit 
    { 
    } 

    public class Apple : Fruit 
    { 
    } 

    public class Orange : Fruit 
    { 
    } 
} 

回答

0

我找到了一個解決方案。在代碼隱藏中,我將爲每個ListBoxItem提供從其可視化子項中找到的上下文菜單。

它使我可以將上下文菜單添加到各個類的DataTemplates中,從而爲我提供了我喜歡的多態性。我也喜歡在XAML中聲明菜單。它適用於鍵盤導航以及鼠標使用。

該代碼可能已被放在附加屬性或東西的優雅。

我添加加載事件處理程序和驗證碼:

void MainWindow_Loaded(object sender, RoutedEventArgs e) 
    { 
     foreach (var item in list.Items) 
     { 
      ListBoxItem lbItem = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem; 
      lbItem.ContextMenu = FindContextMenu(lbItem); 
     } 
    } 

    private ContextMenu FindContextMenu(DependencyObject depObj) 
    { 
     ContextMenu cm = depObj.GetValue(ContextMenuProperty) as ContextMenu; 
     if (cm != null) 
      return cm; 
     int children = VisualTreeHelper.GetChildrenCount(depObj); 
     for (int i = 0; i < children; i++) 
     { 
      cm = FindContextMenu(VisualTreeHelper.GetChild(depObj, i)); 
      if(cm != null) 
       return cm; 
     } 
     return null; 
    } 
1

這傢伙也有類似的問題,因爲你:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5737a331-2014-4e39-b87c-215ae6a7cdd4

而不是爭取焦點,添加一個上下文菜單到列表框。將一個ContextMenuOpening事件處理程序添加到您的列表框中。在該處理程序中,根據當前選定項目的數據上下文,以編程方式添加所需的任何菜單項。

+0

的列表框上下文菜單中的列表框的中間打開,不選定的項目在哪裏。另外,我想在XAML中聲明上下文菜單項,這使得全球化比將其放入代碼更容易。鍵盤焦點對視力受損用戶至關重要,或因其他原因避免使用鼠標的用戶。 – Guge 2010-09-23 11:33:30

3

我也有這個問題。閱讀Bea Stollnitz' blog給了我一個想法。

我開始在我的資源,這樣的數據模板:

<ContextMenu x:Key="MyMenu"> 
    <MenuItem Header="A" /> 
    <MenuItem Header="B" /> 
    <MenuItem Header="C" /> 
</ContextMenu> 

<DataTemplate x:Key="MyTemplateKey" DataType="{x:Type local:myType}"> 
    <TextBlock ContextMenu="{StaticResource MyMenu}" > 
     <Run Text="{Binding Path=MyBindingPath}" FontSize="20" FontWeight="Bold" /> 
    </TextBlock> 
</DataTemplate> 

如上所述,這將導致鍵盤菜單鍵不調用上下文菜單,雖然右擊確實工作。問題是上下文菜單需要在ListBoxItem上,而不是模板裏面。

嘿presto!

<Style x:Key="ContextLBI" TargetType="{x:Type ListBoxItem}"> 
    <Setter Property="ContextMenu" Value="{StaticResource MyMenu}"> 

    </Setter> 
</Style> 

現在,只需從數據模板中刪除文本菜單,並設置你的風格你的列表框這樣的:

<ListBox ItemTemplate="{StaticResource MyTemplateKey}" 
     ItemContainerStyle="{StaticResource ContextLBI}" 
... > 
</ListBox> 
相關問題