【问题标题】:WPF ContextMenu woes: How do I set the DataContext of the ContextMenu?WPF ContextMenu 问题:如何设置 ContextMenu 的 DataContext?
【发布时间】:2013-02-22 21:30:24
【问题描述】:

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

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

我的 Xaml 看起来像这样:

<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>

如何将ContextMenuDataContext设置为item对应的父视图模型?

【问题讨论】:

    标签: wpf contextmenu datacontext


    【解决方案1】:

    ContextMenu 位于可视化树之外。下面是应该为您提供数据上下文的 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 解释了这是如何工作的。

    【讨论】:

    • 这个问题是我不想绑定到 PlacementTarget 是什么。我想绑定到外部控件的DataContext。
    • 你确定他们没有相同的DataContext(即outerControl和inner itemsControl)?
    • 是的,我使用 PlacementTarget 获得的 DataContext 级别太深了。我取回了一个项目,但我需要的是具有包含该项目的集合的视图模型。如果我可以绑定到外部控件的 DataContext,那就完美了。
    • 我猜应该是,我需要Inner ItemsControl的DataContext,但那是Image的外部控件的DataContext。
    • 小心! 不要像我一样将Mode=OneTime 放在ContextMenuDataContext 值上。这将导致绑定由于某种原因而失败。
    【解决方案2】:

    您可以使用标记扩展:

    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>
    

    【讨论】:

    • 好主意,但也许这只适用于ItemsControl 中的菜单?例如,我无法让它在 ContentPresenter 中工作。
    【解决方案3】:

    我不喜欢使用标签。我更喜欢附加属性。

    您需要添加附加属性:

    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>
    

    【讨论】:

      【解决方案4】:

      此代码允许您使用全局和本地 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>
      

      【讨论】:

        猜你喜欢
        • 2014-09-21
        • 2011-07-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-09
        • 1970-01-01
        • 1970-01-01
        • 2010-09-05
        相关资源
        最近更新 更多