WPF ContextMenu со связанными элементами: Items.Count == 0 в событии ContextMenuOpening - PullRequest
2 голосов
/ 12 марта 2010

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

<ContextMenu ItemsSource="{Binding Path=PlacementTarget.SelectedItem,
    RelativeSource={RelativeSource Self}, Converter={StaticResource possibleConverter}}"/>

possibleConverter перечисляет все возможные значения для свойства выбранного элемента, которые отображаются в контекстном меню. В событии Opened контекстного меню я выбираю текущее значение следующим образом:

var cm = e.OriginalSource as ContextMenu;
if (cm != null) {
    var lv = cm.PlacementTarget as ListView;
    var field = lv.SelectedItem as Field;
    var item = cm.ItemContainerGenerator.ContainerFromItem(cm.Items.OfType<object>().Where(o => o.ToString().Equals(field.StringValue)).FirstOrDefault()) as MenuItem;
    if (item != null) {
        item.IsChecked = true;
    }
}

Не особенно элегантно, но работает. С помощью отладчика я убедился, что свойство ContextMenu.Items.Count имеет ненулевое значение, когда ожидается (то есть cm.Items.Count не равно нулю в if).

Пока все хорошо. Однако в представлении списка есть элементы, в которых в контекстном меню не будет элементов. В этом случае отображается пустое меню. Я пытался подавить это в событии ContextMenuOpening в виде списка, например:

var lv = sender as ListView;
if (lv != null) {
    var cm = lv.ContextMenu;
    if ((cm != null) && (cm.Items.Count > 0)) {
        // Here we want to check the current item, which is currently done in the Opened event.
    } else {
        e.Handled = true;
    }
}

Похоже, это должно работать. Однако cm.Items.Count всегда равен нулю. Это верно, даже если ListView.SelectedItem не изменилось: для элемента с пунктами меню меню отображается правильно после первого щелчка, поэтому привязка данных уже произошла. Оно также отображается правильно во второй раз, но в любом случае Items.Count равно нулю в событии ContextMenuOpening.

Что мне не хватает? Как я могу подавить пустые контекстные меню? Почему счетчик нуля в обработчике ContextMenuOpening, который в Windows Forms (ContextMenuStrip.Opening) является канонической точкой, где делать эти вещи?

РЕДАКТИРОВАТЬ: После дальнейшего исследования выясняется, что в обработчике ContextMenuOpening любая привязка к просмотру списка не выполняется, поэтому ItemsSource имеет значение null. Я пытался связать через ElementName, через FindAncestor отношения, все безрезультатно. PlacementTarget является нулевым во время этого события. Хотя уродливый хак сработал: в событии ContextMenuOpening я назначаю представление списка свойству ContextMenu.Tag, в то время как привязка ItemsSource теперь привязывается к Tag.SelectedItem. Это обновляет привязку, поэтому Items.Count так и должно быть. Это все еще странно. Как вы можете сделать значимые вещи в ContextMenuOpening, кроме замены меню или чего-то еще, если привязка не удалась, потому что контекстное меню каким-то образом вышло из контекста во время события? Было ли оно протестировано только со статическими предопределенными пунктами меню?

...