9

Czy istnieje sposób określenia w TreeView 's HierarchicalDataTemplate używania innego ContextMenu w zależności od właściwości danych, do których element jest związany?Zmiana menu kontekstowego w TreeView WPF dla danych

Na przykład, jeśli wyświetlacz jeden ContextMenuItem.IsFile jest prawdą, wyświetlać inną jeśli Item.IsFolder jest prawdą, itp

Odpowiedz

13

To jest przykład dla pola listy, myślę, że można łatwo zmodyfikować go do pracy z 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> 

Kod:

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

wydaje prawie doskonały, dzięki za pełną przykład! – Jared

0

Cześć Robię coś podobnego na TreeView, a ja tego nie lubię ItemToContextMenuConverter jest wykonywany na każdej pozycji, nawet jeśli nie jest używany. Być może jest ok w małym projekcie, ale jeśli dodasz kod Enable/Disable dla każdej MenuItem, to może być wolny.

To może nie najlepszy (właśnie zacząłem z WPF), ale podzielę się nim z wami.

Resources Menu:

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

Kod:

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); 
} 
Powiązane problemy