尝试解包 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()。
我刚开始使用 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()。