我有一些窗口:
<Window>
<ItemsControl ItemsSource="{Binding MyItemList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding ViewModelCommand}">My Button</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
此窗口定义了DataContext
属性,其实例为:
public class MyVM
{
public IEnumerable<FooType> MyItemList { get; set; }
public ICommand ViewModelCommand { get; set; }
}
问题是Button.Command
绑定不起作用。我猜这个问题是因为我的按钮在ItemsControl中,所以绑定在ViewModelCommand
的对象内寻找FooType
。
那么如何正确地进行绑定呢?
答案 0 :(得分:1)
您猜对了:DataContext
内的DataTemplate
将是FooType
项;那是ItemTemplate
的用途:显示每个项目。
当然,问题在于你倾向于在父视图模型上有命令和诸如此类的东西,你需要找到它们(甚至不要跟我谈论上下文菜单)。一种选择是为FooType
viewmodel赋予该命令自己的ViewModelCommand
属性,并让父视图模型为每个项提供对该命令的引用。但那是笨拙和多余的。
我首选的选项是您首先要做的事情:让模板中的XAML绑定到父视图模型的属性。最便携的方法是使用Binding.RelativeSource
向上移动可视树,找到可以预期具有DataContext
的父视图模型的祖先,并使用它来查找父视图模型。它并不理想,但它击败了给予FooType
命令的所有麻烦。
<Button
Command="{Binding DataContext.ViewModelCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
>My Button</Button>
作为一般规则,我们可以依靠ItemsControl
DataContext
作为我们的父视图模型,因为它将ItemsSource
绑定到对象的集合{{1我们可以使用FooType
代替,在你的例子中,如果有充分的理由这样做,但如果是我,我会期待自己或我合作的人复制并粘贴这个XAML,所以我将它保存到绝对最合适的祖先。
您还可以为Window
提供FooType
属性,该属性是对父视图模型的引用:
Parent
如果<Button Command="{Binding Parent.ViewModelCommand}">My Button</Button>
属性类似于Parent
这样的广泛属性,那么该绑定仍然有效,并且您不会过于紧密地联系事物(注意:我最初反对这一点因为我认为Object
将被声明为真正的父视图模型的实际类型。但是如果你没有将它用于视图中的绑定,那么Parent
就可以了)。如果可以的话,我总是喜欢纯XAML。