[英]WPF TreeViewItem Context Menu Unhighlights Item With HierarchicalDataTemplate
我有與此問題相同的問題,我希望TreeViewItem在顯示其上下文菜單時仍看起來處於主動選擇狀態。 但是,在我的樹中,每個級別都有一個不同類型的對象,因此我希望每個級別都有一個不同的ContextMenu。 我正在使用HierachicalDataTemplate完成此操作。 所以我有以下XAML:
<Window x:Class="Project.MainWindow">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Project" ContentRendered="Window_ContentRendered">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="VolumeTemplate">
<StackPanel Orientation="Horizontal">
<Image Source="{StaticResource VolumeIcon}" Margin="3,3,3,3" />
<TextBlock Text="{Binding Path=Name}" Margin="3,3,3,3">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding VolumeTestCommand}"
Header="VolumeTest" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</StackPanel>
</DataTemplate>
<HierachicalDataTemplate x:Key="ServerTemplate"
ItemsSource="{Binding Volumes}"
ItemTemplate="{StaticResource VolumeTemplate}">
<StackPanel Orientation="Horizontal">
<Image Source="{StaticResource ServerIcon}" Margin="3,3,3,3" />
<TextBlock Text="{Binding Name}" Margin="3,3,3,3" >
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding ServerTestCommand}"
Header="ServerTest" />
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
</Grid.Resources>
<TreeView HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{Binding Servers}" Name="tvMain"
ItemTemplate="{StaticResource ServerTemplate}"
PreviewMouseRightButtonDown="tvMain_PreviewMouseRightButtonDown" />
</Grid>
</Window>
后面的代碼:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_ContentRendered(object sender, EventArgs e)
{
//set DataContext here, based on a login dialog
}
static T VisualUpwardSearch<T>(DependencyObject source) where T : DependencyObject
{
DependencyObject returnVal = source;
while (returnVal != null && !(returnVal is T))
{
if (returnVal is Visual || returnVal is Visual3D)
{
returnVal = VisualTreeHelper.GetParent(returnVal);
}
else
{
returnVal = LogicalTreeHelper.GetParent(returnVal);
}
}
return returnVal as T;
}
private void tvMain_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem treeViewItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject);
if(treeViewItem != null)
{
treeViewItem.IsSelected = true;
e.Handled = true;
}
}
}
我嘗試了所引用問題的答案,但我認為它不起作用,因為上下文菜單位於TextBlock而不是TreeViewItem上。 有沒有一種方法可以將ContextMenu附加到DataTemplate中的TreeViewItem上,或者有其他方法可以解決此問題?
我最終不得不創建一個附加屬性,該屬性將上下文菜單從TextBlock移至TreeViewItem:
public static readonly DependencyProperty StealContextMenuProperty =
DependencyProperty.RegisterAttached(
"StealContextMenu",
typeof(bool),
typeof(ParentClass),
new UIPropertyMetadata(false, new PropertyChangedCallback(SCMChanged))
);
public static bool GetStealContextMenu(FrameworkElement obj)
{
return (bool)obj.GetValue(StealContextMenuProperty);
}
public static void SetStealContextMenu(FrameworkElement obj, bool value)
{
obj.SetValue(StealContextMenuProperty, value);
}
public static void SCMChanged(object sender, DependencyPropertyChangedEventArgs e)
{
FrameworkElement fe = sender as FrameworkElement;
if (fe == null) return;
bool value = (bool)e.NewValue;
if (!value) return;
fe.Loaded += new RoutedEventHandler(fe_Loaded);
}
public static void fe_Loaded(object sender, RoutedEventArgs e)
{
FrameworkElement fe = (FrameworkElement)sender;
FrameworkElement child;
child = VisualDownwardSearch<FrameworkElement>(fe, x => x.ContextMenu != null);
if (child != null)
{
fe.ContextMenu = child.ContextMenu;
child.ContextMenu = null;
}
}
public static T VisualDownwardSearch<T>(T source, Predicate<T> match)
where T : DependencyObject
{
Queue<DependencyObject> queue = new Queue<DependencyObject>();
queue.Enqueue(source);
while(queue.Count > 0)
{
DependencyObject dp = queue.Dequeue();
if (dp is Visual || dp is Visual3D)
{
int childrenCount = VisualTreeHelper.GetChildrenCount(dp);
for (int i = 0; i < childrenCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(dp, i);
if (child is T)
{
T tChild = (T)child;
if (match(tChild)) return tChild;
}
queue.Enqueue(child);
}
}
else
{
foreach (DependencyObject child in LogicalTreeHelper.GetChildren(dp))
{
if (child is T)
{
T tChild = (T)child;
if (match(tChild)) return tChild;
}
queue.Enqueue(child);
}
}
}
return null;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.