在WPF TreeView中更改上下文菜单以获取数据

时间:2009-11-20 07:51:10

标签: wpf data-binding treeview contextmenu hierarchicaldatatemplate

有没有办法在TreeView的{​​{1}}中指定使用不同的HierarchicalDataTemplate,具体取决于项目绑定的数据属性?

例如,如果ContextMenu为真,则显示一个ContextMenu,如果Item.IsFile为真,则显示另一个,等等。

2 个答案:

答案 0 :(得分:13)

这是ListBox的示例,我认为您可以轻松修改它以使用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;
    }

答案 1 :(得分:0)

您好我在TreeView上做了类似的事情,我不喜欢即使没有使用也会对每个项目执行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);
}