WPF TreeViewItem 上下文菜单使用 HierarchicalDataTemplate 取消突出显示项目 [英] WPF TreeViewItem Context Menu Unhighlights Item With HierarchicalDataTemplate

查看:22
本文介绍了WPF TreeViewItem 上下文菜单使用 HierarchicalDataTemplate 取消突出显示项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我和这个问题有同样的问题,我想要显示上下文菜单时,TreeViewItem 看起来仍处于主动选中状态.但是,在我的树中,每个级别都有不同类型的对象,因此我希望每个级别都有不同的 ContextMenu.我正在使用 HierachicalDataTemplate 完成此操作.所以我有以下 XAML:

I have the same problem as this question, where I want the TreeViewItem to still look actively selected when its context menu is shown. However, in my tree every level has a different type of object, so I want a different ContextMenu for each level. I'm accomplishing this using the HierachicalDataTemplate. So I have the following 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,或者其他方法来解决这个问题?

I tried the answer from the referenced question, but I think it doesn't work since the context menu is on the TextBlock instead of the TreeViewItem. Is there a way to attach the ContextMenu to the TreeViewItem in the DataTemplate, or another way to address this problem?

推荐答案

我最终不得不创建一个附加属性,它将上下文菜单从 TextBlock 移动到 TreeViewItem:

I ended up having to create an attached property, which moves the context menu from the TextBlock to the 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;      
}

这篇关于WPF TreeViewItem 上下文菜单使用 HierarchicalDataTemplate 取消突出显示项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆