场景:我有一个 ListBox,而 ListBoxItems 有一个 DataTemplate。我想要做的是在 DataTemplate 中放置一个 ContextMenu。问题是我希望这个 ContextMenu ItemsSource 根据窗口中的某些属性而有所不同。我最初的想法是我可以将 ItemsSource 绑定到窗口中的一个属性,然后返回一个 ItemsSource;但是,我似乎无法正确绑定到此属性。我相信这是因为我在 DataTemplate 中,因此 DataContext(我相信这是正确的词)属于那个 ListBoxItem 而不是窗口。如何让 DataTemplate 中的 ContextMenu 绑定到 DataTemplate 之外的属性。
Jasson
问问题
5180 次
2 回答
5
您可以使用 RelativeSource FindAncestor 语法从窗口中获取 DataContext
<DataTemplate>
<TextBlock Text="{Binding MyInfo}">
<TextBlock.ContextMenu>
<Menu ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.MyContextMenuItems}"/>
</TextBlock.ContextMenu>
</TextBlock>
</DataTemplate>
不完全确定,但绑定是正确的......如果您的 DataContext 是另一个对象类型,您只需要更改 AncestorType(例如通过 UserControl)。
于 2009-03-31T21:52:41.527 回答
2
这可能是AttachedProperty的一个很好的候选者。基本上,您要做的是将 ContextMenu 包装在 UserControl 中,然后将 Dependency Property 添加到 UserControl。例如:
MyContextMenu.xaml
<UserControl x:Class="MyContextMenu" ...>
<UserControl.Template>
<ContextMenu ItemSource="{Binding}" />
</UserControl.Template>
</UserControl>
MyContextMenu.xaml.cs
public static readonly DependencyProperty MenuItemsSourceProperty = DependencyProperty.RegisterAttached(
"MenuItemsSource",
typeof(Object),
typeof(MyContextMenu),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static void SetMenuItemsSource(UIElement element, Boolean value)
{
element.SetValue(MenuItemsSourceProperty, value);
// assuming you want to change the context menu when the mouse is over an element.
// use can use other events. ie right mouse button down if its a right click menu.
// you may see a perf hit as your changing the datacontext on every mousenter.
element.MouseEnter += (s, e) => {
// find your ContextMenu and set the DataContext to value
var window = element.GetRoot();
var menu = window.GetVisuals().OfType<MyContextMenu>().FirstOrDefault();
if (menu != null)
menu.DataContext = value;
}
}
public static Object GetMenuItemsSource(UIElement element)
{
return element.GetValue(MenuItemsSourceProperty);
}
Window1.xaml
<Window ...>
<Window.Resources>
<DataTemplate TargetType="ListViewItem">
<Border MyContextMenu.MenuItemsSource="{Binding Orders}">
<!-- Others -->
<Border>
</DataTemplate>
</Window.Resources>
<local:MyContextMenu />
<Button MyContextMenu.MenuItemsSource="{StaticResource buttonItems}" />
<ListView ... />
</Window>
可视化树助手
public static IEnumerable<DependencyObject> GetVisuals(this DependencyObject root)
{
int count = VisualTreeHelper.GetChildrenCount(root);
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(root, i);
yield return child;
foreach (var descendants in child.GetVisuals())
{
yield return descendants;
}
}
}
public static DependencyObject GetRoot(this DependencyObject child)
{
var parent = VisualTreeHelper.GetParent(child)
if (parent == null)
return child;
return parent.GetRoot();
}
这个例子是未经测试的,今晚晚些时候我会看看并确保它是准确的。
于 2009-03-31T21:22:50.210 回答