Свойство ContextMenu isOpen всегда равно false

#c# #wpf #contextmenu

#c# #wpf #contextmenu

Вопрос:

У меня есть кнопка с ContextMenu установленным следующим образом:

 <Button
    x:Name="TestButton"
    Click="TestButton_Click">
    <Button.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Sample Menu Item 1" />
            <MenuItem Header="Sample Menu Item 2" />
            <MenuItem Header="Sample Menu Item 3" />
        </ContextMenu>
    </Button.ContextMenu>
</Button>
  

Код, лежащий в основе:

 private void TestButton_Click(object sender, RoutedEventArgs e)
{
    // This always prints false, even though the contextmenu is currently opened
    System.Console.WriteLine(button.ContextMenu.IsOpen);

    if (sender is Button button)
    {
        button.ContextMenu.Placement = PlacementMode.Bottom;
        button.ContextMenu.PlacementTarget = button;
        button.ContextMenu.StaysOpen = true;
        button.ContextMenu.IsOpen = !button.ContextMenu.IsOpen; // Doesn't work!
    }
}
  

Итак, я настроил ContextMenu на открытие одним щелчком мыши, и это работает, однако я хотел бы переключать ContextMenu видимость при каждом нажатии кнопки. Для этого я хочу использовать IsOpen свойство — присвоить ему значение false, если текущее значение равно true, и наоборот.

Моя проблема в том, что, хотя IsOpen значение свойства устанавливается от false до true при первом нажатии, оно всегда остается false при втором нажатии, как будто оно никогда не будет установлено.

Я предполагаю, что это связано с потерей фокуса (поправьте меня, если я ошибаюсь) — итак, как я могу обойти это и сохранить его помеченным как открытый, пока не произойдет другой щелчок?

Комментарии:

1. @NawedNabiZada Что касается присвоения имени ContextMenu — это так не сработает, результаты те же, что и в текущем коде. Я безуспешно пытался заставить его работать в чистом XAML, следовательно, код позади.

2. Потому что ContextMenu фактически закрывается перед вводом события

Ответ №1:

Я предполагаю, что речь идет о потере фокуса…

Да, свойство ContextMenu ‘s StaysOpen работает не так, как вы ожидаете. Когда вы нажимаете на Button , ContextMenu оно действительно закрывается.

Вы могли бы обойти это, используя DependencyPropertyDescriptor который отслеживает, когда ContextMenu было закрыто, а затем сравнивает прошедшее время с некоторым постоянным значением в вашем обработчике событий. Это должно сработать:

 private DependencyPropertyDescriptor _dpd;
private DateTime _closeTime;

private void TestButton_Click(object sender, RoutedEventArgs e)
{
    if (sender is Button button)
    {
        button.ContextMenu.Placement = PlacementMode.Bottom;
        button.ContextMenu.PlacementTarget = button;
        button.ContextMenu.IsOpen = !button.ContextMenu.IsOpen amp;amp; DateTime.UtcNow.Subtract(_closeTime).TotalMilliseconds > 250;

        if (_dpd == null)
        {
            _dpd = DependencyPropertyDescriptor.FromProperty(ContextMenu.IsOpenProperty, typeof(ContextMenu));
            _dpd.AddValueChanged(button.ContextMenu, OnContextMenuClosed);
        }
    }
}

private void OnContextMenuClosed(object sender, EventArgs e) => _closeTime = DateTime.UtcNow;
  

Ответ №2:

Попробуйте это.

 private bool _isOpen = false;

private void TestButton_Click(object sender, RoutedEventArgs e)
{
    // This always prints false, even though the contextmenu is currently opened
    //System.Console.WriteLine(button.ContextMenu.IsOpen);

    if (sender is Button button)
    {
        if (_isOpen)
        {
            button.ContextMenu.IsOpen = false;
            _isOpen = false;
        }
        else
        {
            button.ContextMenu.Placement = PlacementMode.Bottom;
            button.ContextMenu.PlacementTarget = button;
            button.ContextMenu.StaysOpen = true;
            _isOpen = true;
            button.ContextMenu.IsOpen = _isOpen;
        }
    }
}