我在 WPF 中有一个菜单(带有 menuitems)。不幸的是,当我单击菜单标题时,它会打开右侧的菜单。问题是右边有一些我不希望它重叠的东西。如何告诉 WPF 打开左侧的菜单?我需要做一个控制模板吗?(对于这种基本的样式更改,控件模板似乎过于笨拙)。
谢谢!
KSG
虽然您可以像他们在此处一样创建一个 ControlTemplate 来执行此操作,但我同意仅修改菜单项的一部分上的一个值是一种麻烦的方法。相反,我认为这是使用 AttachedProperty 的好地方。我们可以创建类似于ContextMenuService的东西,但是对于 Popups(事实上,我有点惊讶它不是内置的)。
要更改弹出窗口的打开位置,我们需要设置弹出窗口的 PlacementMode。我们可以使用 propa 快捷方式来生成我们的AttachedProperty(或者如果你想实现其余的属性)。我们需要向 PropertyMetadata 添加回调,但如果在 XAML 中的控件上内联设置了 AttachedProperty,则回调将在整个控件完全构造之前触发。为了确保应用了 MenuItem 的模板,并且在我们尝试设置它的值之前 Popup 存在,如果它尚未加载,我们可以附加到 Loaded 事件。加载后,我们想从模板中检索 Popup,如果我们查看MenuItem 类我们可以看到它有一个 TemplatePartAttribute 将 Popup 的名称定义为“PART_Popup”。一旦我们有了它,我们就可以在 MenuItem 的 Popup 上设置 PlacementMode。
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,很容易在 UI 中更改 Popup 的位置。
<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>