【问题标题】:ContextMenu.PlacementTarget is not getting set, no idea whyContextMenu.PlacementTarget 未设置,不知道为什么
【发布时间】:2011-06-11 23:25:46
【问题描述】:
<DataTemplate x:Key="_ItemTemplateA">
  <Grid Tag="{Binding Path=DataContext.Command, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <ContentControl Content="{Binding}" ContentTemplate="{StaticResource ContentTemplateB}" Grid.Row="0" />
    <ContentControl Name="uiContentPresenter" Content="{Binding ContentView}" Grid.Row="1" Height="0" />
    <ContentControl DataContext="{Binding IsContentDisplayed}" DataContextChanged="IsDisplayed_Changed" Visibility="Collapsed" />
    <Grid.ContextMenu>
      <ContextMenu>
        <MenuItem Header="Text" 
              Command="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}"
              CommandParameter="{Binding}" />
      </ContextMenu>
    </Grid.ContextMenu>
  </Grid>
</DataTemplate>

上面的数据模板被应用到一个ItemsControl。问题是,对于为 Grid 指定的 ContextMenu,PlacementTarget 属性实际上从未设置为任何内容,因此我无法访问 Grid 的 Tag 属性,这是传递应该在父 UserControl 上执行的命令所必需的到上下文菜单。我已经基于类似的例子建立了这种方法,例如:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0244fbb0-fd5f-4a03-bd7b-978d7cbe1be3/

我无法确定任何其他传递此命令的好方法。这是这样设置的,因为我们使用的是 MVVM 方法,因此我们必须执行的命令存在于应用此模板的用户控件的视图模型中。我尝试以几种不同的方式显式设置 PlacementTarget 但它仍然总是显示为未设置。

【问题讨论】:

  • 我也面临同样的问题...任何解决方法。
  • 我也遇到了这个问题。对我来说,它是ListView。我在UserControlLoaded 事件处理程序中放置了一个断点,并检查了&lt;ListView.ContextMenu&gt;PlacementTarget 属性...null。 :(
  • 当我的 ContextMenu 打开时,我也面临 PlacementTarget 为空的问题,导致无法链接回窗口/用户控件中的信息。

标签: wpf xaml wpf-controls binding


【解决方案1】:

我意识到这是旧的并已回答,但似乎没有正确回答。我遇到了similar post 并留下了完整的答案。您可能想看一下,只需对代码进行一些调整即可使其正常工作。

首先,将您的视图命名为UserControl...为简单起见,我通常将我的所有视图命名为This。然后记住我们的视图模型绑定到UserControlDataContext,我们可以使用{Binding DataContext, ElementName=This}绑定到视图模型。

所以现在我们可以绑定到视图模型,我们必须将它与ContextMenu.DataContext 连接起来。我使用对象的Tag 属性和ContextMenuPlacementTarget)作为连接,在本例中为Grid

<DataTemplate x:Key="YourTemplate" DataType="{x:Type DataTypes:YourDataType}">
    <Grid ContextMenu="{StaticResource Menu}" Tag="{Binding DataContext, 
        ElementName=This}">
        ...
    </Grid>
</DataTemplate>

然后,我们可以通过将ContextMenu.DataContext 属性绑定到PlacementTarget.Tag 属性(在我们的示例中为Grid)来访问ContextMenu 中的视图模型属性和命令:

<ContextMenu x:Key="Menu" DataContext="{Binding PlacementTarget.Tag, RelativeSource=
    {RelativeSource Self}}">
    <MenuItem Header="Delete" Command="{Binding DeleteFile}" CommandParameter=
        "{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource 
        AncestorType=ContextMenu}}" CommandTarget="{Binding PlacementTarget, 
        RelativeSource={RelativeSource Self}}" />
</ContextMenu>

注意MenuItem.CommandTarget 属性上的绑定。设置此项可确保引发指定命令的目标元素是PlacementTarget,或在本例中为Grid

还要注意CommandParameter 绑定。这将绑定到PlacementTargetDataContext,或者在这种情况下绑定到GridGridDataContext 将从 DataTemplate 继承,因此如果您正在使用 ICommand 接口的某些实现,则您的数据项现在绑定到 Command 中的 object 参数:

public bool CanExecuteDeleteFileCommand(object parameter)
{
    return ((YourDataType)parameter).IsInvalid;
}

public void ExecuteDeleteFileCommand(object parameter)
{
    Delete((YourDataType)parameter);
}

或者,如果您在视图模型中直接使用某种RelayCommand 委托:

public ICommand Remove
{
    get 
    {
        return new ActionCommand(execute => Delete((YourDataType)execute), 
            canExecute => return ((YourDataType)canExecute).IsInvalid); 
    }
}

【讨论】:

  • 问题是没有设置 PlacementTarget。从原始帖子中的代码示例中,您可以看到问题不是使用 PlacementTarget,而是框架由于某种原因没有设置它!
【解决方案2】:

我们有同样的问题,但它是随机运行的。控件模板内的上下文菜单,以列表框的样式显示。我们尝试将上下文菜单移动到模板内的不同级别,但出现相同的错误。

我们认为这可能与我们的 ICollectionView 的刷新有关,它是 ListBox 的 itemssource。

似乎当视图刷新时,上下文菜单中的相对源绑定在设置 PlacementTarget 之前被评估。

感觉像是collectionviewsource或WPF的ContextMenu中的一个错误......

【讨论】:

  • 你想出解决方案了吗?
【解决方案3】:

这是一个基于您的测试用例的独立 XAML-only 示例:ContextMenu 使用 Tag 从其 PlacementTargetDataContext 检索 Command。您可以重新引入部分代码,直到它停止工作以尝试找出问题所在:

<Grid>
    <Grid.Resources>
        <PointCollection x:Key="sampleData">
            <Point X="10" Y="20"/>
            <Point X="30" Y="40"/>
        </PointCollection>
        <DataTemplate x:Key="_ItemTemplateA">
            <Grid Tag="{Binding Path=DataContext, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DockPanel}}}">
                <TextBlock Text="{Binding X}"/>
                <Grid.ContextMenu>
                    <ContextMenu>
                        <MenuItem Header="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}" CommandParameter="{Binding}"/>
                    </ContextMenu>
                </Grid.ContextMenu>
            </Grid>
        </DataTemplate>
    </Grid.Resources>
    <DockPanel DataContext="{x:Static ApplicationCommands.Open}">
        <ListBox ItemTemplate="{StaticResource _ItemTemplateA}" ItemsSource="{StaticResource sampleData}"/>
    </DockPanel>
</Grid>

【讨论】:

    【解决方案4】:

    在这个post

    当您在按钮上单击鼠标右键时,ContextMenu.PlacementTarget 会从 ContextMenuService.PlacementTarget 填充。

    这意味着 ContextMenu.PlacementTarget 在菜单显示时被填满。您可以通过 snoop 进行检查。

    编辑 1 此代码运行良好。

    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow" BasedOn="{StaticResource DataGridRowBaseStyle}">
            <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=DataContext}"/>
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <ContextMenu Style="{StaticResource ContextMenuStyle}" 
                                 ItemContainerStyle="{StaticResource MenuItemStyle}">
                        <MenuItem Header="Enable" Command="{Binding Path=PlacementTarget.Tag.(viewModels:PrinterListPageViewModel.EnableCommand), RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
                    </ContextMenu>
                </Setter.Value>
            </Setter>
        </Style>
    </DataGrid.RowStyle>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多