1
votes

i'm trying to Bind an ObservableCollection to an ItemsControl. I created a class called Persons with some properties. Then I created a ObservableCollection and add some Persons in there.

If I give the ItemsControl a x:Name="PersonHolder" and add the ItemsSource with PersonHolder.ItemsSource = persons then all works. But if I'm trying to add the persons with a Binding in XAML... no result.

Here is the XAML:

<StackPanel Background="White">
    <ItemsControl ItemsSource="{Binding persons}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

Some code from C#

public ObservableCollection<Person> persons { get; set; }
public MainWindow()
{
    InitializeComponent();
    persons = new ObservableCollection<Person>();
    persons.Add(new Person { Name = "Peter" });
}

public class Person
{
    public string Name { get; set; }
}

Hope you can help me.

Best regards.

3
Where do you set the DataContext of the Control? - MDoobie

3 Answers

3
votes

By default binding will search for property in current DataContext. You need to set binding context, for example by setting DataContext manually in code. However since persons does not raise PropertyChanged event you need to set DataContext after persons is created otherwise UI won't be notified that property has changed

InitializeComponent();
persons = new ObservableCollection<Person>();
//after persons is created
DataContext = this;

without implementing INotifyPropertyChanged, and keeping it in XAML, you can keep single instance of persons

private readonly ObservableCollection<Person> _persons = new ObservableCollection<Person>();

public ObservableCollection<Person> persons { get { return _persons; } }

public MainWindow()
{
    InitializeComponent();      
    persons.Add(new Person { Name = "Peter" });
}

and in XAML

<Window ... x:Name="window">
    <!-- .... -->
    <ItemsControl ... ItemsSource="{Binding ElementName=window, Path=persons}">
1
votes

You'd have to bind it against the control itself:

 <ItemsControl ItemsSource="{Binding persons,  
               RelativeSource={RelativeSource AncestorType={x:Type Window}}}">

Otherwise it binds against DataContext property that has been set to null, right now. You could also set the DataContext in code behind, such as DataContext = this.

All binding errors are in "Output" window.

0
votes

I would rather suggest the following implementation.

Window:

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();
        var context = new SomeContext();
        DataContext = context;
        context.AddPerson();
    }
}

Context:

public class SomeContext 
{
    public ObservableCollection<Person> People { get; set; }

    public SomeContext()
    {
        People = new ObservableCollection<Person>();
        People.Add(new Person { Name = "Samuel" });
    }

    public void AddPerson()
    {
        People.Add(new Person { Name = "Peter" });
    }
}

public class Person
{
    public string Name { get; set; }
} 

XAML:

<Window x:Class="BindingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel Background="White">
            <ItemsControl ItemsSource="{Binding People}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </Grid>
</Window>