我有一个UserControl,它有一个ViewModel,其中包含我自己的自定义类的实例,称之为Person。这个ViewModel被设置为控件的DataContext。我想在我的主窗口中使用这个控件,在它的ViewModel中有一个名为People的类型列表。我在我的xaml中像这样调用控件:
<ItemsControl ItemsSource="{Binding People}">
<ItemsControl.ItemsTemplate>
<DataTemplate>
<userControls:PersonDetails />
</DataTemplate>
</ItemsControl.ItemsTemplate>
</ItemsControl>
控件中的属性以这种方式绑定。
<TextBlock Text="{Binding Person.Name}" />
当我运行时,我得到了列表中人员数量的正确数量的控件,但没有填充详细信息。我知道我做了一些简单的错误,但找不到它。请帮助。
编辑:我的UserControl xaml看起来像这样:
<UserControl x:Class="AddressBook.UserControls.PersonDetails"
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:AddressBook.UserControls"
xmlns:vm="clr-namespace:AddressBook.ViewModels"
xmlns:enums="clr-namespace:AddressBook.Models"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="1000">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="40" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<TextBlock Style="{StaticResource PersonDetailHeader}" Text="Person Name:" />
<TextBlock Style="{StaticResource PersonDetailValue}" Grid.Column="1" Text="{Binding Person.Name,
UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Style="{StaticResource PersonDetailHeader}" VerticalAlignment="Center" Grid.Row="1" Text="Street Address:" />
<TextBlock Style="{StaticResource PersonDetailValue}" Grid.Row="1" Grid.Column="1"
Text="{Binding Person.StreetAddress, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Style="{StaticResource PersonDetailHeader}" Grid.Row="2" Text="Town:" />
<TextBlock Style="{StaticResource PeronDetailValue}" Grid.Row="2" Grid.Column="1"
Text="{Binding Person.Town, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Style="{StaticResource PersonDetailHeader}" Grid.Row="3" Text="County:" />
<TextBlock Style="{StaticResource PersonDetailValue}" Grid.Row="3" Grid.Column="1"
Text="{Binding Person.County, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Style="{StaticResource PersonDetailHeader}" Grid.Row="4" Text="Postcode:" />
<TextBlock Style="{StaticResource PersonDetailValue}" Grid.Row="4" Grid.Column="1"
Text="{Binding Person.Postcode, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Style="{StaticResource PersonDetailHeader}" Grid.Row="5" Text="Phone:" />
<TextBlock Style="{StaticResource PersonDetailValue}" Grid.Row="5" Grid.Column="1"
Text="{Binding Person.Phone, UpdateSourceTrigger=PropertyChanged}" />
<StackPanel Grid.Row="7" Grid.ColumnSpan="2" HorizontalAlignment="Center" Orientation="Horizontal">
<Button Style="{StaticResource ButtonStyle}" Content="Click" Command="{Binding ButtonClickCommand}" />
</StackPanel>
</Grid>
用户控件视图模型:
public class PersonDetailsViewModel
{
public Person Person { get; set; }
public Command ButtonClickCommand { get; }
public PersonDetailsViewModel()
{
ButtonClickCommand = new Command(ButtonClick);
}
private void ButtonClick(object obj)
{
throw new NotImplementedException();
}
UserControl.xaml.cs:
public partial class PersonDetails : UserControl
{
public PersonDetails()
{
InitializeComponent();
}
}
Person.cs
public class Person : BaseModel
{
public string Name
{
get { return name; }
set
{
name = value;
NotifyPropertyChanged();
}
等等……
MainViewModel:
public class MainViewModel : BaseViewModel
{
public ObservableCollection<Person> People { get; }
= new ObservableCollection<Person>();
public MainViewModel()
{
PopulatePeople();
}
}
现在我明白了为什么要在UserControl
XAML中创建PersonDetailsViewModel
,以及该命令的问题所在。
解决这个问题的最简单的方法是使MainViewModel.People
成为PersonDetailsViewModel
的集合而不是Person
。这就是我要做的。
但是如果你想让MainViewModel.People
保持原样,同时仍然在UserControl
内使用PersonDetailsViewModel
,这对我来说是有意义的。你可以这样做:
.xaml
<UserControl
x:Class="AddressBook.UserControls.PersonDetails"
DataContextChanged="PersonDetails_DataContextChanged"
...etc...
>
<!-- Give the Grid a name... -->
<Grid x:Name="OuterGrid">
.xaml.cs
public PersonDetails()
{
InitializeComponent();
}
private void PersonDetails_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// ...so we can give the Grid a different DataContext
OuterGrid.DataContext = new PersonDetailsViewModel {
Person = (Person)this.DataContext
};
}
现在它将继承DataContext
的Person
,但在内部它将基于Person
使用PersonDetailsViewModel
。
不确定这是否是你想要做的。如果您只希望显示您的人员列表中每个人的一些图像,您可以这样做:
<Grid>
<ItemsControl ItemsSource="{Binding People}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" />
<TextBlock Grid.Column="1" Text="{Binding Age}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
将在列表的每个元素的Name属性上绑定Text,因此在列表的每个Person的名称上绑定Text。因为你的ItemsSource已经绑定到People,你的Items的Binding已经在你的List的每个Person上,所以你应该直接调用你的属性为{Binding Name}而不是{Binding Person。名称}