You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中ContextMenu多绑定传递PdfViewerCtrl返回UnsetValue问题

解决ContextMenu中绑定PdfViewerCtrl获取UnsetValue的问题

我太懂你现在的糟心感受了——明明写了两种绑定方式,结果ContextMenu里就是拿不到PdfViewerCtrl的实例,一直返回DependencyProperty.UnsetValue。这其实是WPF里ContextMenu的经典坑:ContextMenu并不属于当前UserControl的可视化树(Visual Tree),它是作为独立的Popup元素存在的,所以你用ElementName或者RelativeSource FindAncestor的方式,根本找不到你的UserControl,自然拿不到目标控件。

下面给你几个可行的解决方案,你可以根据项目情况选:


方案1:借助ContextMenu的PlacementTarget属性

ContextMenu的PlacementTarget指向的是它附着的控件(也就是你的ListBox),而这个ListBox肯定在UserControl的可视化树里,我们可以通过它间接找到UserControl和里面的PdfViewerCtrl:

<ContextMenu>
  <MenuItem Header="Löschen"/>
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="PreviewMouseDown">
      <i:InvokeCommandAction Command="{Binding DeleteAnnotationCmd}">
        <i:InvokeCommandAction.CommandParameter>
          <MultiBinding Converter="{StaticResource MultiBindingConv}">
            <!-- 通过PlacementTarget找到UserControl,再获取PdfViewerCtrl -->
            <Binding RelativeSource="{RelativeSource Mode=Self}" 
                     Path="PlacementTarget">
              <Binding.RelativeSource>
                <RelativeSource Mode="FindAncestor" AncestorType="{x:Type UserControl}"/>
              </Binding.RelativeSource>
              <Binding.Path>PdfViewerCtrl</Binding.Path>
            </Binding>
          </MultiBinding>
        </i:InvokeCommandAction.CommandParameter>
      </i:InvokeCommandAction>
    </i:EventTrigger>
  </i:Interaction.Triggers>
</ContextMenu>

如果你的UserControl的DataContext里已经暴露了PdfViewerCtrl属性,还可以简化成:

<Binding RelativeSource="{RelativeSource Mode=Self}" 
         Path="PlacementTarget.DataContext.PdfViewerCtrl"/>

方案2:把UserControl实例绑定到ContextMenu的DataContext

你可以在ContextMenu加载时,把UserControl的实例绑定到它的DataContext上,后续绑定直接从DataContext取值:

<!-- 先给你的UserControl设置x:Name,比如x:Name="PdfUserCtrl" -->
<UserControl x:Name="PdfUserCtrl" ...>
  <ListBox>
    <ListBox.ContextMenu>
      <ContextMenu DataContext="{Binding ElementName=PdfUserCtrl}">
        <MenuItem Header="Löschen"/>
        <i:Interaction.Triggers>
          <i:EventTrigger EventName="PreviewMouseDown">
            <!-- 注意Command要从UserControl的DataContext里取 -->
            <i:InvokeCommandAction Command="{Binding DataContext.DeleteAnnotationCmd}">
              <i:InvokeCommandAction.CommandParameter>
                <Binding Path="PdfViewerCtrl"/>
              </i:InvokeCommandAction.CommandParameter>
            </i:InvokeCommandAction>
          </i:EventTrigger>
        </i:Interaction.Triggers>
      </ContextMenu>
    </ListBox.ContextMenu>
  </ListBox>
</UserControl>

方案3:使用x:Reference(谨慎选用)

x:Reference可以直接引用XAML中命名的元素,不受可视化树限制,但要注意如果引用的元素还未加载完成可能会出问题,不过对于UserControl来说一般不会有问题:

<!-- 确保你的UserControl已设置x:Name="PdfUserCtrl" -->
<ContextMenu>
  <MenuItem Header="Löschen"/>
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="PreviewMouseDown">
      <i:InvokeCommandAction Command="{Binding DeleteAnnotationCmd}">
        <i:InvokeCommandAction.CommandParameter>
          <MultiBinding Converter="{StaticResource MultiBindingConv}">
            <Binding Source="{x:Reference PdfUserCtrl}" Path="PdfViewerCtrl"/>
          </MultiBinding>
        </i:InvokeCommandAction.CommandParameter>
      </i:InvokeCommandAction>
    </i:EventTrigger>
  </i:Interaction.Triggers>
</ContextMenu>

另外提一句,你原来的MultiBinding里放了两个相同的Binding,其实没必要,选一种能拿到PdfViewerCtrl的方式就行,多绑定可以留着以后需要传多个参数时再用。

内容的提问来源于stack exchange,提问作者Detlef D Soost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:23:23