在itemscontrol中

时间:2016-09-20 14:03:52

标签: c# wpf mvvm data-binding viewmodel

我有一个UserControl,它有一个ViewModel,包含我自己的自定义类的实例,称之为Person。此ViewModel设置为控件的DataContext。我想在我的主窗口中使用此控件,该窗口在其ViewModel中具有名为People的Person类型的List。我在我的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>

UserControl ViewModel:

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();
    }
}

2 个答案:

答案 0 :(得分:1)

现在我明白为什么要在PersonDetailsViewModel XAML中创建UserControl,以及该命令的问题。

解决此问题的最简单方法是使MainViewModel.People成为PersonDetailsViewModel而非Person的集合。这就是我的所作所为。

但是,如果您想要MainViewModel.People保持原样,同时仍然在PersonDetailsViewModel内使用UserControl,那对我来说是有意义的。你可以这样做:

的.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
    };
}

现在它将为Person继承DataContext,但在内部它将使用基于PersonDetailsViewModel的{​​{1}}。

答案 1 :(得分:0)

不确定这是不是你想要做的。 如果您只希望显示人员列表中每个人的某些内容,您可以这样做:

     <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的名称。 由于您的ItemsSource已经绑定到People,因此您的Items的绑定已经在List的每个Person上,因此您应该直接将您的属性称为{Binding Name}而不是{Binding Person.Name}