samedi 25 août 2018

Dynamically add item to ListBox whose DataSource is bound to a collection

I'm trying to create custom reusable WPF UserControl that has a listbox and a button to add a new row, just like how a DataGrid can allow users to add a new row.

This control will be bound to many different types of collections in various view models (i.e. List, ObservableCollection, etc.).

I have the UserControl with a dependency property called DataSource of type IEnumerable (it has to be IEnumerable to allow ObservableCollections, Lists, etc). I want to create a new instance of whatever object is in the underlying collection, and add it to the original collection that is bound to ItemsSource.

I have created a method that will make a new instance of an object that the collection is comprised of:

private object GetNewItem()
{
    if (ItemsSource == null)
        throw new ArgumentException("ItemsSource not set");

    Type itemType = null;
    foreach (Type i in ItemsSource.GetType().GetInterfaces())
    {
        if (i.IsGenericType && i.GetGenericTypeDefinition().Equals(typeof(IEnumerable<>)))
            itemType = i.GetGenericArguments()[0];
    }

    if (itemType == null)
        throw new ArgumentException("Unable to get ItemsSource's Type T");

    return Activator.CreateInstance(itemType);
}

Now I just need to get that new object added to the original collection. Unfortunately, IEnumerable does not allow adding items, as it's not intended to be mutable.

I can detect which type of collection was originally used, i.e.:

if (itemsType.IsGenericType && itemsType.GetGenericTypeDefinition() == typeof(ObservableCollection<>))

So, I can get the type of collection, and that collection's generic type (i.e. collection was an 'ObservableCollection<>', and the generic type was 'Person'), but I cannot figure out how to cast it back... and even if I could, I couldn't add the result of GetNewItem to it as:

((ObservableCollection<Person>) ItemsSource).Add(object) 

... doesn't work without casting object to 'Person'.

DataGrids are able to add a new instance of it's ItemsSource's underlying type, even though it's ItemsSource is IEnumerable, so I know it isn't impossible. I just can't see how to make it work. I would appreciate any advice.





Aucun commentaire:

Enregistrer un commentaire