Динамически добавлять элемент в ListBox, чей DataSource связан с коллекцией - PullRequest
0 голосов
/ 25 августа 2018

Я пытаюсь создать настраиваемый многократно используемый WPF UserControl со списком и кнопкой для добавления новой строки, точно так же, как DataGrid позволяет пользователям добавлять новую строку.

Этот элемент управления будет привязан ко многим различным типам коллекций в различных моделях представления (например, List, ObservableCollection и т. Д.).

У меня есть UserControl со свойством зависимости с именем DataSource типа IEnumerable (он должен быть IEnumerable, чтобы разрешить ObservableCollections, Lists и т. Д.). Я хочу создать новый экземпляр любого объекта в базовой коллекции и добавить его в исходную коллекцию, связанную с ItemsSource.

Я создал метод, который создаст новый экземпляр объекта, из которого состоит коллекция:

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

Теперь мне просто нужно добавить этот новый объект в исходную коллекцию. К сожалению, IEnumerable не позволяет добавлять элементы, поскольку он не предназначен для изменчивости.

Я могу определить, какой тип коллекции изначально использовался, т. Е .:

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

Итак, я могу получить тип коллекции и универсальный тип этой коллекции (т. Е. Коллекция была ObservableCollection <>, а универсальный тип был «Person»), но я не могу понять, как привести ее обратно. .. и даже если бы я мог, я не мог бы добавить результат GetNewItem к нему как:

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

... не работает без приведения объекта в Person.

DataGrids могут добавить новый экземпляр своего базового типа ItemsSource, даже если это ItemsSource IEnumerable, так что я знаю, что это не невозможно. Я просто не вижу, как заставить это работать. Буду признателен за любой совет.

1 Ответ

0 голосов
/ 26 августа 2018

DataGrid добавляет новые элементы с помощью IEditableCollectionView представления на основе ItemsSource: см. исходный код

, поэтому попробуйте привести ItemsSource к IEditableCollectionView и добавить новый элемент, не создавая экземпляр самостоятельно.

var c = CollectionViewSource.GetDefaultView(ItemsSource) as IEditableCollectionView;
if (c != null && c.CanAddNew)
    c.AddNew();

однако этот метод не работал с List<DateTime>, хотя в List есть метод Add: CanAddNew был false. Возможно, это объясняется тем, что DateTime является неизменной структурой.

Этот метод кажется ограниченным, я бы попробовал другой:

Не любой IEnumerable имеет метод Add, который определен в интерфейсе IList. Если ItemsSource не является IList, то ничего нельзя добавить без специальных знаний о конкретном типе. И даже с IList добавление не гарантируется (это может быть ReadOnly или FixedSize (массивы, []))

var c = ItemsSource as IList;
if (c != null && !c.IsReadOnly && !c.IsFixedSize)
    c.Add(newInstance);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...