ContextMenu обрезается в некоторых случаях

В настоящее время я делаю контекстное меню, которое открывается щелчком левой кнопки вместо щелчка правой кнопкой мыши, и для этого я блокирую щелчок правой кнопкой мыши, обрабатывая событие ContextMenuOpening, как это

private void PinBorder_ContextMenuOpening(object sender, System.Windows.Controls.ContextMenuEventArgs e)
{
    e.Handled = true;
}

и я сам открываю контекстное меню для реакции на событие MouseButtonLeftDown, например:

private void PinBorder_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    PinBorder.ContextMenu.PlacementTarget = PinBorder;
    PinBorder.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Center;
    PinBorder.ContextMenu.HorizontalOffset = 0;
    PinBorder.ContextMenu.VerticalOffset = 0;
    PinBorder.ContextMenu.IsOpen = true;
    e.Handled = true;
}

проблема здесь в том, что когда ContextMenu открывается в первый раз, все идет хорошо, но если я добавляю элемент в наблюдаемую коллекцию, привязанную к контекстному меню, и пытаюсь открыть его снова, контекстное меню обрезается до его предыдущего размера (если я пытаюсь Переместить выделение контекстного меню с помощью клавиш вверх / вниз. Я могу догадаться, что запись была создана, но я не вижу ее, потому что она обрезана).

Я попытался удалить материалы, запрещающие клики, и в этом случае все идет хорошо.

Я читал о такой проблеме в.net Framework 3.5, но я ориентируюсь на 4.0.

У кого-нибудь есть решение?

3 ответа

Решение

Если наконец-то нашли обходной путь, чтобы получить то, что я хочу, даже если это решение должно выделять больше памяти, чем необходимо.

Я воссоздаю все контекстное меню каждый раз, когда контекстное меню должно открываться.

private void PinBorder_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    PropertyInputPin.UpdateCompatibleAdjusters();

    PinBorder.ContextMenu = new System.Windows.Controls.ContextMenu();

    Binding binding = new Binding("CompatibleAdjusters");
    binding.Mode = BindingMode.OneWay;
    binding.Source = DataContext;
    BindingOperations.SetBinding(PinBorder.ContextMenu, ContextMenu.ItemsSourceProperty, binding);

    PinBorder.ContextMenu.PlacementTarget = PinBorder;
    PinBorder.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Center;
    PinBorder.ContextMenu.HorizontalOffset = 0;
    PinBorder.ContextMenu.VerticalOffset = 0;
    PinBorder.ContextMenu.IsOpen = true;

    for (int i = 0; i < PropertyInputPin.CompatibleAdjusters.Count; i++)
    {
        MenuItem mi = PinBorder.ContextMenu.ItemContainerGenerator.ContainerFromIndex(i) as MenuItem;
        mi.Click += ContextMenu_Click;
    }

    e.Handled = false;
}

Я не уверен, что ты делаешь неправильно. Следующее работает как мне нужно:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525" x:Name="mainWindow">
    <Window.DataContext>
        <local:Class1></local:Class1>
    </Window.DataContext>
    <Grid x:Name="grid" Background="Blue" MouseLeftButtonDown="Grid_MouseLeftButtonDown" ContextMenuOpening="grid_ContextMenuOpening">
        <Grid.RowDefinitions>
            <RowDefinition Height="200"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ContextMenu>
            <ContextMenu x:Name="contextMenu" ItemsSource="{Binding menuItems}">
            </ContextMenu>
        </Grid.ContextMenu>
        <Button Height="100" Command="{Binding TestCommand}" Grid.Row="1"></Button>
    </Grid>
</Window>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        private List<MenuItem> list;

        public List<MenuItem> menuItems
        {
            get { return list; }
            set { list = value; }
        }

        public MainWindow()
        {
            InitializeComponent();

            list = new List<MenuItem>();
            MenuItem item = new MenuItem();
            item.Header = "One";
            list.Add(item);
            item = new MenuItem();
            item.Header = "Two";
            list.Add(item);
            item = new MenuItem();
            item.Header = "Three";
            list.Add(item);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MenuItem item = new MenuItem();
            item.Header = "Four";
            menuItems.Add(item);
            contextMenu.Items.Add(item);
        }

        private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            grid.ContextMenu.PlacementTarget = grid;
            grid.ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Center;
            grid.ContextMenu.HorizontalOffset = 0;
            grid.ContextMenu.VerticalOffset = 0;
            grid.ContextMenu.IsOpen = true;
            e.Handled = true;
        }

        private void grid_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            e.Handled = true;
        }
    }
}

ViewModel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;

namespace WpfApplication2
{
    public class Class1
    {

        private List<MenuItem> list;

        public List<MenuItem> menuItems
        {
            get { return list; }
            set { list = value; }
        }

        public string test
        {
            get;
            set;
        }

        public Class1()
        {
            test = "1";

            list = new List<MenuItem>();
            MenuItem item = new MenuItem();
            item.Header = "One";
            list.Add(item);
            item = new MenuItem();
            item.Header = "Two";
            list.Add(item);
            item = new MenuItem();
            item.Header = "Three";
            list.Add(item);
            TestCommand = new DelegateCommand(Button_Click);
        }

        public ICommand TestCommand{get;private set;}

        private void Button_Click()
        {
            MenuItem item = new MenuItem();
            item.Header = "Four";
            menuItems.Add(item);
        }
    }
}

Вы можете смоделировать событие следующим образом:

        ContextMenuAutomationPeer peer = new ContextMenuAutomationPeer(Menu);

        IExpandCollapseProvider invokeProv = peer.GetPattern(PatternInterface.ExpandCollapse) as IExpandCollapseProvider;

        invokeProv.Expand();

Однако использование UIAutomation не так просто (и мой пример на самом деле не работает, но должен указать вам верное направление).

Вы также можете попробовать добавить что-то вроде этого к тому, что у вас уже есть (до этого в вашей функции):

        ContextMenuAutomationPeer peer = new ContextMenuAutomationPeer(Menu);

        peer.RaiseAutomationEvent(AutomationEvents.MenuOpened);

Полезная ссылка на MSDN.

Другие вопросы по тегам