9

有没有一种方法可以在TreeViewHierarchicalDataTemplate中指定使用不同的ContextMenu,具体取决于项目所绑定数据的属性?在WPF TreeView中更改数据的上下文菜单

例如,显示一个ContextMenu如果Item.IsFile是真实的,显示不同的一个,如果Item.IsFolder是真的,等

回答

13

这是例如,对于列表框,我认为你可以很容易地修改它与TreeView的工作。

XAML:

... 

<Window.Resources> 
    <ContextMenu x:Key="FileContextMenu"> 
     ... 
    </ContextMenu> 
    <ContextMenu x:Key="DirContextMenu"> 
     ... 
    </ContextMenu> 

    <local:ItemToContextMenuConverter x:Key="ContextMenuConverter" />   
</Window.Resources> 

... 

<ListBox x:Name="SomeList"> 
    <ListBox.ItemTemplate> 
     <DataTemplate>       
      <Label Content="{Binding Path=Name}" ContextMenu="{Binding Converter={StaticResource ContextMenuConverter}}"/> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

代码:

class Item 
{ 
    public string Name { get; set; } 
    public bool IsFile { get; set; } 
} 

[ValueConversion(typeof(Item), typeof(ContextMenu))] 
public class ItemToContextMenuConverter : IValueConverter 
{ 
    public static ContextMenu FileContextMenu; 
    public static ContextMenu DirContextMenu; 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     Item item = value as Item; 
     if (item == null) return null; 

     return item.IsFile ? FileContextMenu : DirContextMenu; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new Exception("The method or operation is not implemented."); 
    } 
} 

private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     ItemToContextMenuConverter.FileContextMenu 
      = this.Resources["FileContextMenu"] as ContextMenu; 
     ItemToContextMenuConverter.DirContextMenu 
      = this.Resources["DirContextMenu"] as ContextMenu; 

     List<Item> items = new List<Item>(); 
     items.Add(new Item() { Name = "First", IsFile = true }); 
     items.Add(new Item() { Name = "Second", IsFile = false }); 

     SomeList.ItemsSource = items; 
    } 
+0

似乎非常完美,感谢完整的例子! – Jared 2009-11-21 17:56:44

0

嗨,我在树视图做类似的事情,像ItemToContextMenuConverter上即使不使用它的每个项目执行我不知道。在一个小项目中也许可以,但是如果为每个MenuItem添加启用/禁用代码,则可能会比较慢。

这可能不是最好的(我刚开始使用WPF),但我会与你分享。

菜单资源:

<Window.Resources> 
    <ContextMenu x:Key="MnuFolderFavorites" StaysOpen="True"> 
    <MenuItem Header="Remove from Favorites" Click="MnuFolder_RemoveFromFavorites_Click"></MenuItem> 
    </ContextMenu> 
    <ContextMenu x:Key="MnuFolder" StaysOpen="True"> 
    <MenuItem Header="New Folder"></MenuItem> 
    <MenuItem Header="Rename" x:Name="MnuFolderRename" Click="MnuFolder_Rename_Click"></MenuItem> 
    <MenuItem Header="Add to Favorites" Click="MnuFolder_AddToFavorites_Click"></MenuItem> 
    </ContextMenu> 
</Window.Resources> 

的TreeView:

<TreeView x:Name="TvFolders"> 
    <TreeView.ItemTemplate> 
    <HierarchicalDataTemplate DataType="{x:Type data:Folder}" ItemsSource="{Binding Items}"> 
     <StackPanel Orientation="Horizontal" PreviewMouseRightButtonDown="TvFoldersStackPanel_PreviewMouseRightButtonDown"> 
     <Image Width="20" Height="20" Source="{Binding ImagePath}" /> 
     <TextBlock Text="{Binding Title}" Margin="5,0,0,0" /> 
     </StackPanel> 
    </HierarchicalDataTemplate> 
    </TreeView.ItemTemplate> 
</TreeView> 

代码:

private void TvFoldersStackPanel_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { 
    ((StackPanel) sender).ContextMenu = null; 
    Data.Folder item = (Data.Folder) ((StackPanel) sender).DataContext; 
    if (!item.Accessible) return; 
    if (item.Parent != null && item.Parent.Title.Equals("Favorites")) { 
    ((StackPanel) sender).ContextMenu = MainWindow.Resources["MnuFolderFavorites"] as ContextMenu; 
    } else { 
    ((StackPanel) sender).ContextMenu = MainWindow.Resources["MnuFolder"] as ContextMenu; 
    foreach (MenuItem menuItem in ((StackPanel) sender).ContextMenu.Items) { 
     switch (menuItem.Name) { 
     case "MnuFolderRename": { 
      menuItem.IsEnabled = item.Parent != null; 
      break; 
     } 
     } 
    } 
    } 
} 

private void MnuFolder_RemoveFromFavorites_Click(object sender, RoutedEventArgs e) { 
    string path = ((Data.Folder)((MenuItem)sender).DataContext).FullPath; 
    Settings.Default.FolderFavorites.Remove(path); 
    Settings.Default.Save(); 
    FavoritesFolder?.AddFavorites(true); 
}