Jens
Jens

Reputation: 2702

Bind the ItemsSource of a DataGrid to a List

I am trying to create a binding between a List and a DataGrid. I haven't found a working Solution in the net which is very strange.

In my little example I create a List of objects with the two public properties Age and Name:

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

    public int Age { get; set; }
}

public ObservableCollection<Person> Collection { get; set; } 

public List<Person> Persons { get; set; }

private void WindowLoaded(object sender, RoutedEventArgs e)
{

    this.Persons = new List<Person>();

    for (int i = 0; i != 35; i++)
    {
        this.Persons.Add(new Person() {Age = i, Name = i.ToString()});
    }

    this.Collection = new ObservableCollection<Person>(this.Persons);
}

The XAML Code looks like this:

<Grid DataContext="{Binding ElementName=TestWindow, Path=.}">
    <DataGrid x:Name="DataGrid" ItemsSource="{Binding Collection}" />
</Grid>

or this (both is not working):

<Grid DataContext="{Binding ElementName=TestWindow, Path=.}">
        <DataGrid x:Name="DataGrid" ItemsSource="{Binding Persons}" />
</Grid>

if I use this.DataGrid.ItemsSource = this.Persons; I see at least all the items in the list but I have to this.DataGrid.Items.Refresh() every time the Source List changes which is the reason why I ask the question:

What am I doing wrong? Do I need to implement INotifyPropertyChanged?

This question must be very easy to answer but it would be also awesome to understand the mechanics.

Upvotes: 5

Views: 35530

Answers (3)

d.moncada
d.moncada

Reputation: 17402

Okay, so the reason why you are having issues is because what happens when the window is loaded and how the data binding is set up.

The ItemsSource of the DataGrid doesn't happen until the Window has already loaded (it's getting set in your Window loaded event). So as a result, the DataGrid does not now that it's ItemsSource has changed. You can fix this by adding INotiftyProperty changed to the list itself, or, you can create the DataGrid list first, and just populate when the Window has loaded.

For example:

xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        Collection = new ObservableCollection<Person>();
        InitializeComponent();
    }

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

        public int Age { get; set; }
    }

    public ObservableCollection<Person> Collection { get; set; }

    public List<Person> Persons { get; set; }

    private void WindowLoaded(object sender, RoutedEventArgs e)
    {

        this.Persons = new List<Person>();

        for (int i = 0; i != 35; i++)
        {
            this.Persons.Add(new Person() { Age = i, Name = i.ToString() });
        }

        foreach (var p in Persons)
        {
            Collection.Add(p);
        }
    }
}

xaml:

<Window x:Class="WpfApplication1.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"
        x:Name="TestWindow"
        Loaded="WindowLoaded">
    <Grid DataContext="{Binding ElementName=TestWindow, Path=.}">
        <DataGrid x:Name="DataGrid" ItemsSource="{Binding Collection}" />
    </Grid>
</Window>

Upvotes: 5

Jens
Jens

Reputation: 2702

After a very long day of coding I was too nervous and tired. the solution is very easy:

Implement the INotifyPropertyChanged Interface for the Person class:

public class Person: INotifyPropertyChanged
{
    private string name;

    private int age;

    public string Name
    {
        get
        {
            return this.name;
        }
        set
        {
            this.name = value;
            this.OnPropertyChanged("Name");
        }
    }

    public int Age
    {
        get
        {
            return this.age;
        }
        set
        {
            this.age = value;
            this.OnPropertyChanged("Age");
        }
    }

    protected void OnPropertyChanged(string name)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

And then bind the Data with these Code behind:

this.DataGrid.DataContext = this.Persons;

For a successful Binding you need also these XAML Code:

<DataGrid x:Name="DataGrid" ItemsSource="{Binding}" />

The valuesin the DataGrid will now refresh whenever the Data in one of the Person instances changes.

Upvotes: 2

scubasteve623
scubasteve623

Reputation: 647

I do a similar thing a ton in Windows Forms Apps with data grid views. So maybe this can point you in the right direction... I don't have much experience with wpf.

List<Connection> connList = new List<Connection>();
//populate list somehow
BindingSource bs = new BindingSource();
bs.DataSource = connList;
DataGrid.DataSource = bs;           



    public class Connection
    {
        public string Name {get; set;}
        public string Connect {get; set;}

        public Connection(string n, string c)
        {
            Name = n;
            Connect = c;
        }
    }

Upvotes: 0

Related Questions