Как заставить меню открываться слева в WPF? - PullRequest
3 голосов
/ 18 июня 2009

У меня есть меню (с пунктами меню) в WPF. К сожалению, когда я нажимаю на заголовок меню, он открывает меню справа. Проблема в том, что справа есть вещи, которые я не хочу перекрывать. Как мне сказать WPF открыть меню слева? Нужно ли делать контрольный шаблон? (шаблоны управления кажутся такими сложными для таких базовых изменений стиля).

Спасибо!

KSG

1 Ответ

12 голосов
/ 18 июня 2009

Хотя вы можете создать ControlTemplate для этого, как они делают здесь , я согласен, что это громоздкий метод - просто изменить одно значение в части MenuItems. Вместо этого я думаю, что это отличное место для использования AttachedProperty. Мы можем создать что-то вроде ContextMenuService , но для всплывающих окон (на самом деле, я несколько удивлен, что это не встроено).

Чтобы изменить место открытия всплывающего окна, нам нужно установить PlacementMode. Мы можем использовать ярлык propa для генерации нашего AttachedProperty (или свойств, если вы хотите реализовать все остальное). Нам нужно добавить обратный вызов в нашу PropertyMetadata, но если AttachedProperty установлен встроенным в элементе управления в XAML, обратный вызов будет запущен до того, как весь элемент управления будет полностью построен. Чтобы убедиться, что шаблон MenuItem применен, и всплывающее окно существует до того, как мы попытаемся установить его значение, мы можем просто прикрепить событие Loaded, если оно еще не загружено. Как только он загружен, мы хотим извлечь Popup из шаблона, и если мы посмотрим на класс MenuItem , мы увидим, что у него есть TemplatePartAttribute, определяющий имя Popup как «PART_Popup». Получив это, мы можем установить PlacementMode во всплывающем окне MenuItem.

    public static PlacementMode GetMenuPlacement(DependencyObject obj)
    {
        return (PlacementMode)obj.GetValue(MenuPlacementProperty);
    }

    public static void SetMenuPlacement(DependencyObject obj, PlacementMode value)
    {
        obj.SetValue(MenuPlacementProperty, value);
    }

    // Using a DependencyProperty as the backing store for MenuPlacement.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MenuPlacementProperty =
        DependencyProperty.RegisterAttached("MenuPlacement",
        typeof(PlacementMode),
        typeof(Window1),
        new FrameworkPropertyMetadata(PlacementMode.Bottom, FrameworkPropertyMetadataOptions.Inherits, new PropertyChangedCallback(OnMenuPlacementChanged)));

    private static void OnMenuPlacementChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
        var menuItem = o as MenuItem;
        if (menuItem != null)
        {
            if (menuItem.IsLoaded)
            {
                SetPopupPlacement(menuItem, (PlacementMode)e.NewValue);
            }
            else
            {
                menuItem.Loaded += new RoutedEventHandler((m, v) => SetPopupPlacement(menuItem, (PlacementMode)e.NewValue));
            }
        }
    }

    private static void SetPopupPlacement(MenuItem menuItem, PlacementMode placementMode)
    {
        Popup popup = menuItem.Template.FindName("PART_Popup", menuItem) as Popup;
        if (popup != null)
        {
            popup.Placement = placementMode;
        }
    }

Теперь, когда у нас есть AttachedProperty, можно легко изменить размещение всплывающих окон в пользовательском интерфейсе.

<Menu>
    <MenuItem Header="Item 1"
              local:Window1.MenuPlacement="Right">
        <MenuItem Header="SubItem 1" />
        <MenuItem Header="SubItem 2" />
        <MenuItem Header="SubItem 3" />
        <MenuItem Header="SubItem 4" />
    </MenuItem>
    <MenuItem Header="Item 2"
              local:Window1.MenuPlacement="Left">
        <MenuItem Header="SubItem 5" />
        <MenuItem Header="SubItem 6" />
        <MenuItem Header="SubItem 7" />
        <MenuItem Header="SubItem 8" />
    </MenuItem>
    <MenuItem Header="Item 3"
              local:Window1.MenuPlacement="Mouse">
        <MenuItem Header="SubItem 9" />
        <MenuItem Header="SubItem 10" />
        <MenuItem Header="SubItem 11" />
        <MenuItem Header="SubItem 12" />
    </MenuItem>
</Menu>
...