ContextMenu для элемента ListBox с DataTemplate - PullRequest
2 голосов
/ 19 сентября 2010

У меня есть ListBox с различными классами предметов. Шаблоны данных используются для представления этих объектов соответствующим образом. Я хочу иметь разные контекстные меню в шаблонах данных этих классов.

Все отлично работает с помощью мыши, но с помощью клавиатуры я не могу вызвать контекстное меню.

Вероятно, это связано с тем, что фокус клавиатуры находится не на содержимом шаблона данных, а на элементе ListBoxItem.

Как я могу получить ListBoxItem для ссылки на ContentMenu контента?

Пример кода:

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

Ответы [ 3 ]

3 голосов
/ 09 апреля 2011

У меня тоже была эта проблема. Чтение блога 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>
1 голос
/ 22 сентября 2010

У этого парня такая же проблема, как и у вас: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5737a331-2014-4e39-b87c-215ae6a7cdd4.

Вместо того, чтобы бороться с фокусом, добавьте контекстное меню в список.Добавьте обработчик события ContextMenuOpening в свой список.В этом обработчике, в зависимости от контекста данных выбранного в данный момент элемента, добавьте все необходимые элементы меню программно.

0 голосов
/ 23 сентября 2010

Я нашел решение.В коде я предоставлю каждому 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;
    }
...