Change context menu in WPF TreeView for data Change context menu in WPF TreeView for data wpf wpf

Change context menu in WPF TreeView for data


This is example for ListBox, I think you can easily modify it to work with 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>

Code:

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;    }


Hi I am doing similar thing on TreeView and I don't like that ItemToContextMenuConverter is executed on each item even if it is not used. It's maybe ok in a small project but if you add Enable/Disable code for each MenuItem than it can be slow.

This is maybe not the best (I just started with WPF), but I will share it with you.

Menu Resources:

<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>

Code:

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);}