绑定到ItemsControl中的Window.DataContext.ViewModelCommand

时间:2016-05-05 01:15:42

标签: c# .net wpf

我有一些窗口:

<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

那么如何正确地进行绑定呢?

1 个答案:

答案 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。