尝试解包 ViewModel 时出现绑定问题

Binding issues when attempting to unwrap ViewModel

我刚开始使用 WPF,并试图了解如何正确设置 MVVM。目前我有一个 UserControl,它有一个 ListBox。列表框包含一个复选框列表,选中时我想显示一个包含与该复选框关联的用户控件的 TabItem。首先,我找到了一种创建 CheckListBox here 的方法,但现在当我尝试创建标签页时,我得到了与 TabControls ItemsSource 相关的绑定异常:

System.Windows.Data Error: 40 : BindingExpression path error: 'Items' property not found on 'object' ''DataTemplate' (HashCode=22018304)'. BindingExpression:Path=Items.CheckedItems; DataItem='DataTemplate' (HashCode=22018304); target element is 'TabControl' (Name='tc_TabItems'); target property is 'ItemsSource' (type 'IEnumerable')

System.Windows.Data Error: 40 : BindingExpression path error: 'selectedItem' property not found on 'object' ''DataTemplate' (HashCode=22018304)'. BindingExpression:Path=selectedItem; DataItem='DataTemplate' (HashCode=22018304); target element is 'TabControl' (Name='tc_TabItems'); target property is 'SelectedItem' (type 'Object')

我的MainWindow.xaml:

<Window x:Class="CheckListBox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CheckListBox"
    Title="MainWindow" Height="350" Width="525">

<Window.Resources>
    <DataTemplate DataType="{x:Type local:TabItemViewModel}">
        <local:TabItemUserControl />
    </DataTemplate>

    <DataTemplate x:Key="TabHeader" DataType="{x:Type local:TabItemViewModel}">
        <TextBlock Text="{Binding Value.Name}"/>
    </DataTemplate>

</Window.Resources>

<Grid Background="#FFE5E5E5">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
        <ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding selectedItem}" Margin="4" SelectionMode="Extended" >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <CheckBox Name="check" IsChecked="{Binding IsChecked, Mode=TwoWay}" Margin="3" VerticalAlignment="Center" />
                    <ContentPresenter Content="{Binding Value.Name}" Margin="1"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <StackPanel Grid.Column="1" >
        <TextBlock FontWeight="Bold" >Selected Items</TextBlock>
        <ItemsControl Grid.Column="1" Margin="4"  x:Name="items" ItemsSource="{Binding Path=Items.SelectedItems}" DisplayMemberPath="Value.Name" />
    </StackPanel>
    <TabControl Name="tc_TabItems" Grid.Column="2" TabStripPlacement="Right" 
                ItemsSource="{Binding Items.SelectedItems}" 
                SelectedItem="{Binding selectedItem}"
                >
        <TabControl.ItemTemplate>
            <DataTemplate DataType="{x:Type local:TabItemViewModel}">
                <TextBlock Text="{Binding Value.Name}"/>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.DataContext>
            <DataTemplate>
                <TabItem Content="{Binding Value}"></TabItem>
            </DataTemplate>
        </TabControl.DataContext>
    </TabControl>

</Grid>

如果我删除 TabControl.DataContext 那么绑定错误就会消失,并且会出现具有适当 header 的 TabItems,但显然 DataContext 是空的。

MainWindow.xaml.cs:

    ...            
    public MainWindow () {
        InitializeComponent();
        this.DataContext = new ViewModel();
    }

视图模型:

    private TabItemViewModel _selectedItem;
    private CheckableObservableCollection<TabItemViewModel> _items;

    public CheckableObservableCollection<TabItemViewModel> Items { get { return _items; } set { SetField( ref _items, value ); } }
    public TabItemViewModel selectedItem { get { return _selectedItem; }  set {SetField(ref _selectedItem, value); }}            

    public ViewModel () {
    //Items = new CheckableObservableCollection<TabItemUserControl> { "this", "is", "a", "test" };
        Items = new CheckableObservableCollection<TabItemViewModel>();
        Items.Add( new TabItemViewModel { Name = "Name", Temp = "Temp1" } );
        Items.Add( new TabItemViewModel { Name = "Nameington", Temp = "Temp2" } );
        Items.Add( new TabItemViewModel { Name = "NameNameington", Temp = "Temp3" } );

*我省略了 CheckableObservableCollection 和 CheckWrapper,因为它们与 link 中的大部分相同。我觉得 TabItemViewModel 并不是真正必要的,因为它的 collection 属性可以在 ViewModel 示例

中设置和使用

澄清以上错误仅在存在 TabControl.DataContext 时发生(如果我删除该部分,输出中不会出现错误)。

报错告诉你问题所在:

'Items' property not found on 'object' ''DataTemplate' (HashCode=22018304)'

您将 TabControl.DataContext 设置为 DataTemplate。 DataTemplate 没有 Items 属性 所以你得到错误。

您似乎希望 ViewModel 成为 DataContext。所以,只要不在 TabControl 上设置 DataContext,它将继承其父级的 DataContext。它会冒泡直到它到达 Window,它具有您在代码中设置的 DataContext,new ViewModel()。