为什么这个ListView CheckBox绑定到整个viewmodel而不是行项?

时间:2016-11-20 06:31:28

标签: c# wpf listview mvvm

我有ListView

<Window.DataContext>
    <vm:PersonPickListViewModel />
</Window.DataContext>
....
<ListView Grid.Row="0" Grid.Column="0" ItemsSource="{Binding PeopleOptions}" IsEnabled="{Binding ListEnabled}" SelectionMode="Multiple" >
    <ListView.View>
        <GridView>
            <GridViewColumn>
                <GridViewColumn.HeaderTemplate>
                    <DataTemplate>
                        <CheckBox DataContext="{Binding ElementName=PersPickList, Path=DataContext}" IsChecked="{Binding AllSelected}" Command="{Binding ToggleSelectAll}"  CommandParameter="{Binding ElementName=PersPickList, Path=DataContext}" />
                    </DataTemplate>
                </GridViewColumn.HeaderTemplate>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <CheckBox IsChecked="{Binding IsSelected}" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="Name" DisplayMemberBinding="{Binding GivenName}" />
        </GridView>
    </ListView.View>
</ListView>

标题模板的DataContext复选框是具体的,我假设在本地,设置为整个视图模型PersonPickListViewModel,因为AllSelected是该模态的属性,而不是列表项对象,即PeopleOptions的成员,即PickListPerson

由于PickListPerson.IsSelected绑定在单元格模板中,我猜它会假设其行的数据上下文,而不是其标题。当我输入&#34; Path&#34;在Binding之后,我会获得所有PersonPickListViewModel属性的列表,而不是所需的PickListPerson属性。

我做错了什么,我该如何解决呢?

3 个答案:

答案 0 :(得分:2)

我认为您的问题无效,因为您错误地假设所讨论的CheckBox未绑定到行项目,而实际上。我认为,在定义绑定时, XAML设计器建议主视图模型的成员而不是项目视图模型会误导您。设计师不是一个完美的工具,它只是试图猜测数据上下文在运行时会是什么,但它经常会出错 - 就像你的情况一样。

如果我没有弄错,它会假设数据上下文将继承,因为它来自 XAML 结构:

CheckBox ← GridViewColumn ← GridView ← ListView ← ... ← Window

但在运行时,GridViewColumn.CellTemplate数据模板用作ContentPresenter.ContentTemplateContentPresenter.Content是行项。 ContentPresenterGridViewRowPresenter的孩子,它代表一个单元格。因此,在运行时,模板化数据实际上是您的项目视图模型。

答案 1 :(得分:0)

您是否忘了在ListView上设置x:Name="PersPickList"?我无法在控件中找到它的名字。设置DataContext="{Binding ElementName=PersPickList, Path=DataContext}"时,您指定复选框上的每个其他绑定都应在指定的PersPickList控件的datacontext中找到其源。如果在VisualTree中找不到该元素,则可能会导致问题。

理想情况下,GridView标头从父控件继承datacontext,但单元格从Row继承datacontext。我设法通过在ListView上设置x:Name并允许IsSelected,AllSelected属性通过INotifyPropertyChanged接口通知视图来使代码工作。不用INotifyPropertyChanged填充更改也可以打破它。但除此之外,它应该有效。

答案 2 :(得分:0)

您可以尝试这样做

<DataTemplate>
    <CheckBox IsChecked="{Binding PersPickList.AllSelected}" Command="{Binding PersPickList.ToggleSelectAll}"  CommandParameter="{Binding PersPickList}" />
</DataTemplate>

同样,您应该发布所有您的视图模型代码,因为 更容易确定哪些内容错误。