绑定到ViewModels集合的WPF无法按预期显示
我的同事和我一直在拼命地想弄明白为什么我们不能得到一组ViewModels来按预期进行渲染。我们创建了一个非常简单的示例来演示这个问题 基本上,我们有一个StupidPerson类,它有一个名字和一个朋友列表(也是StupidPerson的)。在MainViewModel中,我们创建根StupidPerson,并向他的朋友添加四个其他StupidPerson。主窗口仅显示使用StupidPersonViewModel的源StupidPerson StupidPersonView模型拥有所有的功能,StupidPersonView背后的代码甚至实现了DependencyProperty。StupidPersonView将ItemsControl的ItemsSource绑定到StupidPersonViewModel的StupidFriends属性 为了尝试所有不同的可能性,我们确实把事情复杂化了。我希望从下面的XAML中看到的是“Name:Fred”,后面是“Friends:”,后面是四个“Name:XXXX”和空的“Friends:”列表。然而,我得到的是4个空的StupidPerson 现在的情况是,XAML magic没有使用我在MainViewModel中创建的StupidPersonViewModel(绑定到ItemsSource),而是新建了四个空的StupidPersonViewModel,并将它们用于要渲染的项目。它显然绑定到我创建的列表,因为它只渲染4个空的ViewModels 完全困惑绑定到ViewModels集合的WPF无法按预期显示,wpf,data-binding,itemssource,Wpf,Data Binding,Itemssource,我的同事和我一直在拼命地想弄明白为什么我们不能得到一组ViewModels来按预期进行渲染。我们创建了一个非常简单的示例来演示这个问题 基本上,我们有一个StupidPerson类,它有一个名字和一个朋友列表(也是StupidPerson的)。在MainViewModel中,我们创建根StupidPerson,并向他的朋友添加四个其他StupidPerson。主窗口仅显示使用StupidPersonViewModel的源StupidPerson StupidPersonView模型拥有所有的功能
<UserControl x:Class="StupidXaml.StupidPersonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:StupidXaml"
mc:Ignorable="d"
d:DesignHeight="300"
Background="White" Width="509.016">
<UserControl.DataContext>
<local:StupidPersonViewModel />
</UserControl.DataContext>
<StackPanel>
<Label Content="{Binding Name}" />
<Label Content="Friends:" />
<ItemsControl Margin="10,0,0,0" ItemsSource="{Binding StupidFriends}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:StupidPersonView />
</DataTemplate>
<!--<DataTemplate DataType="local:StupidPersonViewModel">
<StackPanel Orientation="Horizontal">
--><!-- Proves that binding is a StupidPersonViewModel --><!--
<Label Content="{Binding}"></Label>
--><!-- Both of these work! --><!--
<Label Content="{Binding Name}"></Label>
<Label Content="{Binding Person.Name}"></Label>
--><!-- But none of these work. How is this possible!? -->
<!-- DataContext binding -->
<!--<local:StupidPersonView DataContext="{Binding}" />
<local:StupidPersonView DataContext="{Binding DataContext, ElementName=item}" />-->
<!-- Dependency Property binding -->
<!--<local:StupidPersonView Person="{Binding Person}" />
<local:StupidPersonView Person="{Binding DataContext.Person, ElementName=item}" />
<local:StupidPersonView Person="{Binding DataContext.Person, ElementName=item, BindsDirectlyToSource=True}" x:Name="self" />--><!--
</StackPanel>
</DataTemplate>-->
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
显示以下内容:
这个XAML
<UserControl x:Class="StupidXaml.StupidPersonView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:StupidXaml"
mc:Ignorable="d"
d:DesignHeight="300"
Background="White" Width="509.016">
<UserControl.DataContext>
<local:StupidPersonViewModel />
</UserControl.DataContext>
<StackPanel>
<Label Content="{Binding Name}" />
<Label Content="Friends:" />
<ItemsControl Margin="10,0,0,0" ItemsSource="{Binding StupidFriends}">
<ItemsControl.ItemTemplate>
<!--<DataTemplate>
<local:StupidPersonView />
</DataTemplate>-->
<DataTemplate DataType="local:StupidPersonViewModel">
<StackPanel Orientation="Horizontal">
<!--Proves that binding is a StupidPersonViewModel-->
<Label Content="{Binding}"></Label>
<!--Both of these work!-->
<Label Content="{Binding Name}"></Label>
<Label Content="{Binding Person.Name}"></Label>
<!--But none of these work. How is this possible!?-->
<!--DataContext binding-->
<local:StupidPersonView DataContext="{Binding}" />
<local:StupidPersonView DataContext="{Binding DataContext, ElementName=item}" />
<!--Dependency Property binding-->
<local:StupidPersonView Person="{Binding Person}" />
<local:StupidPersonView Person="{Binding DataContext.Person, ElementName=item}" />
<local:StupidPersonView Person="{Binding DataContext.Person, ElementName=item, BindsDirectlyToSource=True}" x:Name="self" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
显示以下内容:
public类主视图模型
{
公共StupidPersonViewModel源{get;set;}
公共主视图模型()
{
Source=new StupidPersonViewModel{Person=new StupidPerson{Name=“Fred”};
Source.Person.StupidFriends.Add(新的StupidPerson{Name=“Bob”});
Source.Person.StupidFriends.Add(新的StupidPerson{Name=“Greg”});
Source.Person.StupidFriends.Add(新的StupidPerson{Name=“Frank”});
Source.Person.StupidFriends.Add(新的StupidPerson{Name=“Tommy”});
}
}
公共类StupidPersonViewModel:INotifyPropertyChanged
{
[CanBeNull]
公共字符串名称=>$“名称:{this.Person?.Name}”;
个人;
[CanBeNull]
公众人物
{
获取{返回this.person;}
设置
{
这个人=价值;
此.RaiseProperty已更改(此人的姓名);
this.StupidFriends=新的ObservableCollection();
foreach(值为var friend.StupidFriends)
{
this.StupidFriends.Add(新的StupidPersonViewModel{Person=friend});
}
this.RaisePropertyChanged(Name of(this.Name));
this.RaisePropertyChanged(this.StupidFriends的名字);
}
}
私有void RaisePropertyChanged(字符串属性)
{
本协议项下的不动产变更(不动产);
}
私人可观察收集的朋友;
公众可观察收集愚蠢的朋友
{
获取{返回this.stupidFriends;}
设置
{
this.stupidFriends=值;
this.RaisePropertyChanged(this.StupidFriends的名字);
}
}
//公共StupidPersonViewModel()
//{
//}
//公共StupidPerson视图模型(StupidPerson-person)
//{
//这个人=人;
//}
公共事件属性更改事件处理程序属性更改;
[NotifyPropertyChangedInvocator]
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
this.PropertyChanged?.Invoke(this,newpropertychangedeventargs(propertyName));
}
}
UserControl实现中的一个常见错误是显式地将其DataContext
属性设置为预期视图模型的实例,就像您通过
<UserControl.DataContext>
<local:StupidPersonViewModel />
</UserControl.DataContext>
这样做可以有效地防止UserControl从其父控件继承DataContext,如中所预期的那样
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:StupidPersonView />
</DataTemplate>
</ItemsControl.ItemTemplate>
其中继承的DataContext是ItemsSource
集合的元素
这里的继承意味着
所以不要显式地设置UserControl的DataContext。从未。任何告诉您这一点的博客或在线教程都是完全错误的。用户控件实现中的一个常见错误是显式地将其
DataContext
属性设置为预期视图模型的实例,就像您通过
<UserControl.DataContext>
<local:StupidPersonViewModel />
</UserControl.DataContext>
这样做可以有效地防止UserControl从其父控件继承DataContext,如中所预期的那样
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:StupidPersonView />
</DataTemplate>
</ItemsControl.ItemTemplate>
其中继承的DataContext是ItemsSource
集合的元素
这里的继承意味着
所以不要显式地设置UserControl的DataContext。从未。任何博客或在线教程告诉您这一点都是完全错误的。您是否应该首先创建StupidPerson Fred和Fred的朋友,然后创建viewmodel并分配Person属性,因为您在StupidPerson viewmodel中的Person设置器中有逻辑来创建StupidPerson列表中的ViewModels?您是否应该首先创建StupidPerson Fred和Fred的朋友,然后创建viewmodel并指定Person属性,因为您在StupidP中的Person setter中有逻辑