WPF ContextMenu困境:如何设置ContextMenu的DataContext?

时间:2013-02-22 21:30:25

标签: wpf contextmenu datacontext

我在查明如何在DataContext上设置正确的ContextMenu时遇到了一些麻烦。

我有一组视图模型,它们是ItemsControl的来源。每个视图模型都有一组项目,这些项目也是另一个ItemsControl的来源。每个项目用于绘制具有ContextMenu的图像。 MenuItems中的ContextMenu需要绑定到视图模型上的命令,但PlacementTarget的{​​{1}}指向单个项目。

我的Xaml看起来像这样:

ContextMenu

如何将<ItemsControl ItemsSource="{Binding Markers"}> <ItemsControl.ItemTemplate> <DataTemplate> <ItemsControl ItemsSource="{Binding Items}"> <ItemsControl.ItemTemplate> <DataTemplate> <Image> <Image.ContextMenu> <ContextMenu> <MenuItem Header="Edit" Command="{Binding EditCommand}" /> </ContextMenu> </Image.ContextMenu> </Image> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> 的{​​{1}}设置为项目的相应父视图模型?

4 个答案:

答案 0 :(得分:39)

ContextMenu位于可视树之外。下面是应该为您提供datacontext的xaml:

<ItemsControl ItemsSource="{Binding Markers}" Tag="{Binding ElementName=outerControl, Path=DataContext}">
   ...
   <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
      <MenuItem Header="Edit"
                Command="{Binding EditCommand}" />
   </ContextMenu>
   ...
</ItemsControl>

post解释了这是如何运作的。

答案 1 :(得分:15)

您可以使用markupextension:

using System;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Xaml;

[MarkupExtensionReturnType(typeof(ContentControl))]
public class RootObject : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider));
        return rootObjectProvider?.RootObject;
    }
}

它可以让你:

<ItemsControl ItemsSource="{Binding Markers}">
   ...
   <ContextMenu DataContext="{Binding DataContext, Source={local:RootObject}}">
      <MenuItem Header="Edit"
                Command="{Binding EditCommand}" />
   </ContextMenu>
   ...
</ItemsControl>

答案 2 :(得分:2)

我不喜欢使用Tag。我更喜欢附属物。

您需要添加附加属性:

public static readonly DependencyProperty DataContextExProperty = DependencyProperty.RegisterAttached("DataContextEx", typeof(Object), typeof(DependencyObjectAttached));

    public static Object GetDataContextEx(DependencyObject element)
    {
        return element.GetValue(DataContextExProperty);
    }

    public static void SetDataContextEx(DependencyObject element, Object value)
    {
        element.SetValue(DataContextExProperty, value);
    }

在XAML中:

<Button attached:DependencyObjectAttached.DataContextEx="{Binding ElementName=MyDataContextElement, Path=DataContext}">
        <Button.ContextMenu>
            <ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.(attached:DependencyObjectAttached.DataContextEx)}">

            </ContextMenu>
        </Button.ContextMenu>
    </Button>

答案 3 :(得分:0)

此代码允许您同时使用全局和本地DataContext(用于整个userControl和当前TreeViewItem):

<TreeView Grid.Row="0" ItemsSource="{Binding Path=SelectableEnterprises}">
<TreeView.ItemTemplate>
    <HierarchicalDataTemplate ItemsSource="{Binding Children}">
        <Grid Height="20" Tag="{Binding DataContext, ElementName=userControl}">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="25"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.ContextMenu>
                <ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}" >
                    <ContextMenu.Visibility>
                        <MultiBinding Converter="{converters:SurveyReportVisibilityConverter}">
                            <Binding Path="DataContext"/> <!--local DataContext-->
                            <Binding Path="Tag.SelectedSurvey"/> <!--global DataContext-->
                        </MultiBinding>
                    </ContextMenu.Visibility>

                    <MenuItem Header="Show HTML-report" Command ="{Binding Tag.OpenHTMLReportCommand}" 
                              CommandParameter="{Binding DataContext}" />
                </ContextMenu>
            </Grid.ContextMenu>