所以我只是设置一个项目,并添加了一个自定义的UserControl,如下所示。
<Grid>
<ItemsControl ItemsSource="{Binding UserViewModel.Users}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<controls:UserCard/>
<TextBlock Text="{Binding Name}"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
如您所见,我尝试绑定Text
属性,但它没有绑定。
现在,可能会有很多原因说明它的行为,所以我将尝试缩小范围。
我创建了一个BaseViewModel,它将保存我的ViewModel,看起来像这样。
public class BaseViewModel : ObservableObject
{
public UserViewModel UserViewModel { get; set; } = new UserViewModel();
}
然后我像这样设置ViewModel
public class UserViewModel : ObservableObject
{
public ObservableCollection<User> Users { get; set; } = new ObservableCollection<User>();
public UserViewModel()
{
Users.Add(new User{Name = "Riley"});
Users.Add(new User{Name = "Riley1"});
}
}
简单,现在我有一个类似这样的ObservableObject并处理了INPC
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
在我的MainView.xaml
中
我已经像这样设置了DataContext
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new BaseViewModel();
}
}
与UserControl完全相同
这是我实际添加UserControl的地方,以便它显示在MainWindow中
<ItemsControl ItemsSource="{Binding UserViewModel.Users}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<controls:UserCard/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
现在的问题是它不绑定数据,我想显示模型中的Name
属性,但不显示它,并且我不确定为什么,如果我尝试将其绑定到直接在MainView中使用TextBlock属性,效果很好。
我不确定为什么会这样,我想理解为什么。 我需要利用DependencyProperties吗?还是我创建BaseViewModel的新实例的一种情况?我哪里出错了?
答案 0 :(得分:1)
您的MainViewWindow
包含一个带有绑定ItemsSource="{Binding UserViewModel.Users}"
的ItemsControl,每个项目都显示一个<controls:UserCard/>
。但是您的用户控件随后尝试使用"{Binding UserViewModel.Users}"
再次绑定到列表。您为什么要在另一个列表中显示一个列表?
我怀疑这里的问题是您认为自定义UserControl的DataContext
仍指向BaseViewModel,就像其父级一样。不是。 ItemsControl中每个项目的DataContext
指向列表中它自己的关联元素,即类型为User
的实例。
已更新:假设您有一个带有子视图模型列表的主视图模型,如下所示:
public class MainViewModel : ViewModelBase
{
public MyChildViewModel[] MyItems { get; } =
{
new MyChildViewModel{MyCustomText = "Tom" },
new MyChildViewModel{MyCustomText = "Dick" },
new MyChildViewModel{MyCustomText = "Harry" }
};
}
public class MyChildViewModel
{
public string MyCustomText { get; set; }
}
假设您将MainWindow的DataContext设置为MainViewModel的实例并添加ListView:
<ListView ItemsSource="{Binding MyItems}" />
如果执行此操作,则会看到以下内容:
这里发生的是ListView正在为列表中的三个元素中的每个创建一个容器(类型为ContentPresenter),并将每个人的DataContext设置为指向其自己的MyChildViewModel实例。默认情况下,ContentPresenter只是在其DataContext上调用“ ToString()”,因此您只看到它指向的类的名称。如果像这样向您的MyChildViewModel中添加ToString()
运算符:
public override string ToString()
{
return $"MyChildViewModel: {this.MyCustomText}";
}
...然后您会看到显示的内容:
您还可以完全覆盖ListViewItem的模板,并且由于它已经指向与其关联的MyChildViewModel实例,因此您可以直接绑定到其属性:
<ListView ItemsSource="{Binding MyItems}">
<ListView.ItemTemplate>
<DataTemplate>
<!-- One of these gets created for each element in the list -->
<Border BorderBrush="Black" BorderThickness="1" Background="CornflowerBlue" CornerRadius="5" Padding="5">
<TextBlock Text="{Binding MyCustomText}" Foreground="Yellow" />
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
将哪个显示更改为:
有道理吗?