我在WPF应用程序中使用M-V-VM模式。我将ViewModel绑定到ContentControl并使用窗口资源中定义的数据模板来呈现该ViewModel的视图(UserControl)。
在ViewModel中,我有一组项目。我将该集合绑定到WPF工具包中提供的数据网格。同样在视图模型中,我定义了一个RemoveItem命令,该命令接受要删除的项ID的参数。
如何在数据网格中绑定该命令?网格的数据上下文就是那个集合,所以类似于:
<Button Command="{Binding Path=RemoveCommand}" CommandParameter="{Binding Path=id}">X</Button>
不起作用 - 它无法找到命令。我想我需要做RelativeSource绑定,但那会是什么样子? Ancestor类型是UserControl还是ContentControl?我的ViewModel作为DataContext驻留在哪里?
还是我离开这里?
答案 0 :(得分:37)
是的,你只需要升级一级。我首先尝试与ElementName
绑定,并在必要时使用RelativeSource
。例如,我更喜欢这个:
<DataGrid x:Name="_grid">
...
<Button Command="{Binding DataContext.RemoveItem, ElementName=_grid}"/>
...
</DataGrid>
也就是说,当涉及到元素名称和控件的作用域时,XAML编译器可以得到一个结,所以你可能需要诉诸RelativeSource
:
<DataGrid x:Name="_grid">
...
<Button Command="{Binding DataContext.RemoveItem,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type DataGrid}}
}"/>
...
</DataGrid>
您只需要搜索,直到数据上下文成为您的视图模型。如果您愿意,可以搜索UserControl
- 不确定它真的很重要。两者都是相当脆弱的绑定,这就是我更喜欢ElementName
方法的原因。
答案 1 :(得分:1)
我喜欢在名称为ViewModel的控件的datacontext中定义viewmodel。使用ElementName
更容易编写绑定...
<UserControl.DataContext>
<local:UserControlViewModel x:Name="ViewModel"/>
</UserControl.DataContext>
...
...
<DataGridTemplateColumn Width="30">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding RemoveCommand, ElementName=ViewModel}"
CommandParameter="{Binding}">Remove</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
...
请注意,在这种情况下,Command Parameter是行的整个数据对象。有时比
更好CommandParameter="{Binding Id}"
因为您不必再次查找数据。