在WPF TreeView中更改数据的上下文菜单
问题描述:
有没有一种方法可以在TreeView
的HierarchicalDataTemplate
中指定使用不同的ContextMenu
,具体取决于项目所绑定数据的属性?在WPF TreeView中更改数据的上下文菜单
例如,显示一个ContextMenu
如果Item.IsFile
是真实的,显示不同的一个,如果Item.IsFolder
是真的,等
答
这是例如,对于列表框,我认为你可以很容易地修改它与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;
}
答
嗨,我在树视图做类似的事情,像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);
}
似乎非常完美,感谢完整的例子! – Jared 2009-11-21 17:56:44