在项控件中绑定用户控件

本文关键字:控件 用户 绑定 | 更新日期: 2023-09-27 18:07:49

我有一个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
    };
}

现在它将继承DataContextPerson,但在内部它将基于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。名称}