WPF: Implementing and binding (datagrid) to a custom collection

13,140

Solution 1

Apparently, in order for AutoGenerateColumns to work in a WPF DataGrid, your collection has to implement IItemProperties, although I've found that wrapping my collection in a (windows forms) BindingList does the trick as well (it actually wraps your collection, unlike the ObservableCollection which just copies your collections' members into itself).

Solution 2

I think you using your knowlege of Windows Forms by writing dataGrid1.DataContext = persons; In WPF DataGrid is connected to the collection (say List) very simple: dataGrid1.ItemsSource = persons;

Solution 3

What is your MyCollection<T> type adding over List<T>? Either way, I would use an ObservableCollection instead (so that the UI is notified of additions/removals), and implement INotifyPropertyChanged on your Person class so that the UI is notified of changes to that type's property values.

EDIT

I don't think it's particularly trivial binding to your own custom collection type. You'll need to implement INotifyPropertyChanged and INotifyCollectionChanged on that type. This article might be of some use - http://www.e-pedro.com/2009/04/creating-a-custom-observable-collection-in-wpf/

Another option if you are using MVVM, is to use your custom collection type on your model, and use a standard ObservableCollection on your view model and populate your view models collection from your model, then bind your grid to your view models collection.

Share:
13,140
joniba
Author by

joniba

Updated on July 09, 2022

Comments

  • joniba
    joniba almost 2 years

    I have a custom collection that I am passing to a WPF client, which is binding the collection to a datagrid using AutoGenerateColumns="True". The datagrid, however, is displaying empty rows (albeit the right number of empty rows). What am I doing wrong? Following is some sample code. For now I've omitted everything having to do with INotifyPropertyChanged and INotifyCollectionChanged because, well, I first want to have some data showing up in the grid.

    I should also mention that I've tried implementing the above two interfaces, but they seem to have nothing to do with this issue.

    (You might not actually want to look at the sample code as there's absolutely nothing interesting about it. The collection implementation is just wrapping an inner List.)

    Some random POCO:

    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    

    Simple collection implementation:

    public class MyCollection<T> : IList<T>
    {
        private List<T> list = new List<T>();
    
        public MyCollection()
        {
        }
    
        public MyCollection(IEnumerable<T> collection)
        {
            list.AddRange(collection);
        }
    
     #region ICollection<T> Members
    
        public void Add(T item)
        {
           list.Add(item);
        }
    
        public void Clear()
        {
           list.Clear();
        }
    
        public bool Contains(T item)
        {
            return list.Contains(item);
        }
    
        public void CopyTo(T[] array, int arrayIndex)
        {
           list.CopyTo(array, arrayIndex);
        }
    
        public int Count
        {
           get { return list.Count; }
        }
    
        public bool IsReadOnly
        {
            get { return false; }
        }
    
        public bool Remove(T item)
        {
           return list.Remove(item);
        }
    
    #endregion
    
    #region IEnumerable<T> Members
    
        public IEnumerator<T> GetEnumerator()
        {
            return list.GetEnumerator();
        }
    
    #endregion
    
    #region IEnumerable Members
    
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
    #endregion
    
    #region IList<T> Members
    
        public int IndexOf(T item)
        {
            return list.IndexOf(item);
        }
    
        public void Insert(int index, T item)
        {
           list.Insert(index, item);
        }
    
        public void RemoveAt(int index)
        {
           list.RemoveAt(index);
        }
    
        public T this[int index]
        {
           get { return list[index]; }
           set { list[index] = value; }
        }
    
       #endregion
    } 
    

    The XAML:

    <Window x:Class="TestWpfCustomCollection.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <DataGrid AutoGenerateColumns="True" 
                      HorizontalAlignment="Stretch" 
                      Name="dataGrid1" VerticalAlignment="Stretch" 
                      ItemsSource="{Binding}" 
            />
        </Grid>
    </Window>
    

    The window's code-behind:

    public MainWindow()
    {
         InitializeComponent();
    
         MyCollection<Person> persons = new MyCollection<Person>()
         {
             new Person(){FirstName="john", LastName="smith"},
             new Person(){FirstName="foo", LastName="bar"}
         };
    
         dataGrid1.DataContext = persons;
    }
    

    By the way, if you change the code-behind to use a List<Person> instead of the MyCollection<Person>, everything works as expected.

    EDIT:

    The above code is not taken from the real situation. I have only posted it to show what I am doing in order to test my problem and to make it easier to replicate it. The actual custom collection object is quite complex and I cannot post it here. Again, I'm just trying to understand the basic concept behind what needs to be done in order for a datagrid to properly bind to a custom collection and automatically generate columns for the underlying objects.