具有 DataTemplate 的列表框项上的上下文菜单

发布于 2024-09-19 17:01:13 字数 2037 浏览 11 评论 0原文

我有一个包含不同类别项目的列表框。数据模板用于以适当的方式呈现这些对象。我想在这些类的 DataTemplates 中有不同的上下文菜单。

使用鼠标一切正常,但使用键盘我无法调出上下文菜单。

这可能是因为键盘焦点不在 DataTemplate 的内容上,而是在 ListBoxItem 上。

如何让 ListBoxItem 引用内容的 ContextMenu?

示例代码:

<Window x:Class="WpfApplication8.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:WpfApplication8"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate DataType="{x:Type my:Orange}">
        <TextBlock>
            Orange
            <TextBlock.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Peel"/>
                </ContextMenu>
            </TextBlock.ContextMenu>
        </TextBlock>
    </DataTemplate>
    <DataTemplate DataType="{x:Type my:Apple}">
        <TextBlock>
            Apple
            <TextBlock.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Uncore"/>
                </ContextMenu>
            </TextBlock.ContextMenu>
        </TextBlock>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Fruits}"/>
</Grid>
</Window>


using System.Windows;
using System.Collections.ObjectModel;

namespace WpfApplication8
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Fruits = new ObservableCollection<Fruit>();
            Fruits.Add(new Apple());
            Fruits.Add(new Apple());
            Fruits.Add(new Orange());
            this.DataContext = this;
        }

        public ObservableCollection<Fruit> Fruits { get; set; }
    }

    public class Fruit
    {
    }

    public class Apple : Fruit
    {
    }

    public class Orange : Fruit
    {
    }
}

I have a ListBox with different classes of items. DataTemplates are used to present those objects in the appropriate way. I want to have different context menus in the DataTemplates of these classes.

Everything works fine using the mouse, but using the keyboard I can't bring up the context menu.

This is probably because the keyboard-focus is not on the contents of the DataTemplate, but on the ListBoxItem.

How can I get the ListBoxItem to refer to the Content's ContextMenu?

Sample code:

<Window x:Class="WpfApplication8.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:my="clr-namespace:WpfApplication8"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate DataType="{x:Type my:Orange}">
        <TextBlock>
            Orange
            <TextBlock.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Peel"/>
                </ContextMenu>
            </TextBlock.ContextMenu>
        </TextBlock>
    </DataTemplate>
    <DataTemplate DataType="{x:Type my:Apple}">
        <TextBlock>
            Apple
            <TextBlock.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Uncore"/>
                </ContextMenu>
            </TextBlock.ContextMenu>
        </TextBlock>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Fruits}"/>
</Grid>
</Window>


using System.Windows;
using System.Collections.ObjectModel;

namespace WpfApplication8
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Fruits = new ObservableCollection<Fruit>();
            Fruits.Add(new Apple());
            Fruits.Add(new Apple());
            Fruits.Add(new Orange());
            this.DataContext = this;
        }

        public ObservableCollection<Fruit> Fruits { get; set; }
    }

    public class Fruit
    {
    }

    public class Apple : Fruit
    {
    }

    public class Orange : Fruit
    {
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不甘平庸 2024-09-26 17:01:13

我也有这个问题。阅读 Bea Stollnitz 的博客给了我一个想法。

我从我的资源中的这样的数据模板开始:

<ContextMenu x:Key="MyMenu">
    <MenuItem Header="A" />
    <MenuItem Header="B" />
    <MenuItem Header="C" />
</ContextMenu>

<DataTemplate x:Key="MyTemplateKey" DataType="{x:Type local:myType}">
   <TextBlock ContextMenu="{StaticResource MyMenu}" >
        <Run Text="{Binding Path=MyBindingPath}" FontSize="20" FontWeight="Bold" />
   </TextBlock>
</DataTemplate>

如上所述,这会导致键盘菜单键不调用上下文菜单,尽管右键单击确实有效。问题是上下文菜单需要位于 ListBoxItem 上,而不是内部模板上。

嘿,快点!

<Style x:Key="ContextLBI" TargetType="{x:Type ListBoxItem}">
    <Setter Property="ContextMenu" Value="{StaticResource MyMenu}">

    </Setter>
</Style>

现在,只需从数据模板中删除 ContextMenu,然后在列表框中设置样式,如下所示:

<ListBox ItemTemplate="{StaticResource MyTemplateKey}" 
         ItemContainerStyle="{StaticResource ContextLBI}"
... >
</ListBox>

I too had this problem. Reading Bea Stollnitz' blog gave me an idea.

I started with a data template like this in my resources:

<ContextMenu x:Key="MyMenu">
    <MenuItem Header="A" />
    <MenuItem Header="B" />
    <MenuItem Header="C" />
</ContextMenu>

<DataTemplate x:Key="MyTemplateKey" DataType="{x:Type local:myType}">
   <TextBlock ContextMenu="{StaticResource MyMenu}" >
        <Run Text="{Binding Path=MyBindingPath}" FontSize="20" FontWeight="Bold" />
   </TextBlock>
</DataTemplate>

As described above, this causes the keyboard menu key not to invoke the context menu, although right clicking does work. The problem is the context menu needs to be on the ListBoxItem, not the template inside.

Hey presto!

<Style x:Key="ContextLBI" TargetType="{x:Type ListBoxItem}">
    <Setter Property="ContextMenu" Value="{StaticResource MyMenu}">

    </Setter>
</Style>

Now, just remove the ContextMenu from the data template, and set your style on your list box like this:

<ListBox ItemTemplate="{StaticResource MyTemplateKey}" 
         ItemContainerStyle="{StaticResource ContextLBI}"
... >
</ListBox>
£烟消云散 2024-09-26 17:01:13

这家伙和你有类似的问题: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5737a331-2014-4e39-b87c-215ae6a7cdd4

不要与焦点争斗,而是向列表框中添加上下文菜单。将 ContextMenuOpening 事件处理程序添加到列表框。在该处理程序中,根据当前所选项目的数据上下文,以编程方式添加您需要的任何菜单项。

This guy have similar problem as you: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5737a331-2014-4e39-b87c-215ae6a7cdd4.

Instead of fighting with focus, add a context menu to the listbox. Add a ContextMenuOpening event handler to your listbox. In that handler, depending on data context of currently selected item, add whatever menuitems you need programmatically.

弱骨蛰伏 2024-09-26 17:01:13

我找到了解决方案。在代码隐藏中,我将为每个 ListBoxItem 提供从其可视子项中找到的上下文菜单。

它使我可以将上下文菜单添加到各种类的 DataTemplates 中,从而提供了我喜欢的多态性。我也更喜欢在 XAML 中声明菜单。它适用于键盘导航以及鼠标使用。

为了优雅起见,代码可能会被放入附加属性或其他东西中。

我添加一个已加载的事件处理程序和以下代码:

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        foreach (var item in list.Items)
        {
            ListBoxItem lbItem = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
            lbItem.ContextMenu = FindContextMenu(lbItem);
        }
    }

    private ContextMenu FindContextMenu(DependencyObject depObj)
    {
        ContextMenu cm = depObj.GetValue(ContextMenuProperty) as ContextMenu;
        if (cm != null)
            return cm;
        int children = VisualTreeHelper.GetChildrenCount(depObj);
        for (int i = 0; i < children; i++)
        {
            cm = FindContextMenu(VisualTreeHelper.GetChild(depObj, i));
            if(cm != null)
                return cm;
        }
        return null;
    }

I found a solution. In the code-behind I will give each ListBoxItem the context menu I find from its visual children.

It gives me the possibility of adding the context menus to the DataTemplates for the various class, thus giving me the polymorphism I like. I also prefer to declare the menus in XAML. And it works with keyboard navigation, as well as mouse use.

The code could probably have been put in an attached property or something for elegance.

I add a loaded event handler and this code:

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        foreach (var item in list.Items)
        {
            ListBoxItem lbItem = list.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
            lbItem.ContextMenu = FindContextMenu(lbItem);
        }
    }

    private ContextMenu FindContextMenu(DependencyObject depObj)
    {
        ContextMenu cm = depObj.GetValue(ContextMenuProperty) as ContextMenu;
        if (cm != null)
            return cm;
        int children = VisualTreeHelper.GetChildrenCount(depObj);
        for (int i = 0; i < children; i++)
        {
            cm = FindContextMenu(VisualTreeHelper.GetChild(depObj, i));
            if(cm != null)
                return cm;
        }
        return null;
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文