在DataTemplate中绑定到父级DataContext

7

我正在尝试将 MenuItem 的 Command 绑定到包含在 UserControl.DataContext 中的命令。我找到了几个类似的问题,但根据它们提供的解决方案对我来说无法实现:

<UserControl ...>
<UserControl.Resources>
    <DataTemplate x:Key="TileItemStye">
        <Grid Width="100" Height="100">
            <Grid.ContextMenu>
                <ContextMenu>
                    <MenuItem Header="Remove" 
                              Command="{Binding DataContext.RemoveItem, 
                              RelativeSource={RelativeSource FindAncestor,
                                             AncestorType=UserControl}}">
                    </MenuItem>
                </ContextMenu>
            </Grid.ContextMenu>
        </Grid>
    </DataTemplate>
</UserControl.Resources>
<Grid>
    <ListView ItemsSource="{Binding Path=Files}" 
              ItemTemplate="{DynamicResource TileItemStye}"  >
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
</ListView>
</Grid>

UserControl的DataContext是带有RemoveItem和ObservableCollection<FileViewModel> Files的ViewModel。


你的程序出了什么问题?请解释一下你遇到的错误。 - Random Dev
命令未绑定...我没有收到任何错误,只是绑定到命令的处理程序从未被调用。 - bkovacic
1
我认为Datacontext应该直接“降落”到您的模板上,您尝试过Command =“{Binding Path = RemoveItem}”吗? - hyp
2个回答

13
如果你在使用 .NET 4,确实有一个更加优雅的解决方案:
<UserControl Name="uc" ...>
<!-- ... -->
    <MenuItem Header="Remove"
              Command="{Binding DataContext.RemoveItem,
                                Source={x:Reference uc}}"/>

(这需要模板保留在资源中,否则将会产生循环依赖错误)


您能详细说明依赖项错误吗?我有一个类似的情况,我正在使用 ElementName=LayoutRoot 来获取 DataContext(我的 ViewModel)。但是它会泄漏 ViewModel。这是否是您所说的循环依赖错误?有没有解决办法?(顺便说一句,这是 Windows Store 应用程序) - Joris Weimar
@JorisWeimar:只有在从其树中引用控件时才会出现依赖项错误,例如如果一个Grid包含一个TextBlock并且您尝试在TextBlock的绑定中引用Grid,那么就会导致此类错误。我之所以在这里使用x:Reference,是因为在断开的树上下文中,ElementName无法工作。关于您的问题,我不明白“泄漏视图模型”应该是什么意思。 - H.B.
泄漏ViewModel的意思是,ViewModel没有完成,因为在COM层内部有对它的引用(根据PerfView收集的信息)。这似乎是这种构造方式固有的问题。 - Joris Weimar

4

菜单不会在与您的控件相同的可视树中绘制,这就是为什么RelativeSource绑定无法工作的原因。

您需要绑定到您的ContextMenuPlacementTarget以访问主要的可视树。

<MenuItem Header="Remove" 
          Command="{Binding PlacementTarget.DataContext.RemoveItem, 
              RelativeSource={RelativeSource FindAncestor, 
              AncestorType={x:Type ContextMenu}}}" />

嗯...我仍然无法调用命令。我知道你的意思,但绑定不起作用。 - bkovacic
@Pedala 我可能语法有误。我知道你想绑定到 PlacementTarget,它应该返回 ContextMenu 所附加的控件,但你可能需要使用不同的语法来导航到命令。 - Rachel
你编写的绑定只到达了 Grid(DataTemplate 中的那个),但没有到达 UserControl 的 DataContext(命令所在的位置)。问题是是否可以嵌套绑定,以便我可以从这个 Grid 向上移动? - bkovacic
@pedala 我不认为这是不可能的,但你可以尝试使用RelativeSource绑定将ContextMenu.DataContext绑定到UserControl的DataContext - Rachel
我已将Grid的Tag属性绑定到{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}, Path=DataContext},并将MenuItem绑定到{Binding PlacementTarget.Tag.RemoveItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}}。目前可以正常工作,但我相信仍有更优雅的解决方案... - bkovacic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接