Заполнение коллекции в XAML

Как заполнить коллекцию через интерфейс? Вот XAML:

    <local:ViewModel>
        <local:Test Text="Hmm!"/>
    </local:ViewModel>

Вот модель, которая работает:

[ContentProperty("Tests")]
public class ViewModel
{
    public List<Test> Tests { get; } = new List<Test>();
}

Где:

public class Test
{
    public string Text { get; set; }
}

Я хотел бы пойти с интерфейсом, хотя:

[ContentProperty("Tests")]
public class ViewModel
{
    public IList<Test> Tests { get; } = new List<Test>();
}

К сожалению, не компилируется:

Невозможно установить свойство содержимого «Тесты» для элемента «ViewModel». «Тесты» имеют неправильный уровень доступа или его сборка не разрешает доступ.

На самом деле я создаю экземпляр PostSharp AdvisableCollection<T> и не хочу, чтобы клиентский код зависел от него.


person Dmitry Nogin    schedule 16.09.2018    source источник
comment
Похоже, ошибка подразумевает, что вам нужно добавить метод доступа set к вашим тестам, поскольку вы пытаетесь установить коллекцию в своем xaml?   -  person Mac    schedule 16.09.2018
comment
Нет, это не так. Он добавляет к List<T> { get; }, но не может скомпилировать IList<T> { get; }.   -  person Dmitry Nogin    schedule 16.09.2018
comment
Просто поясню: WPF отлично работает с {get; } только при заполнении свойств коллекции. Распространенная ошибка думать иначе. К сожалению, нет надлежащей поддержки универсальных интерфейсов — эта технология слишком долго находится в зомби-режиме.   -  person Dmitry Nogin    schedule 17.09.2018


Ответы (1)


XAML обрабатывается с использованием определений типов, присутствующих в XAML. Он не имеет видимости фактически используемых экземпляров.

Процессор XAML использует неуниверсальный интерфейс IList для добавления элементов в коллекцию, а процессор генерирует код. Поскольку интерфейс IList<T> не реализует ни один из этих интерфейсов, элементы нельзя добавлять в коллекцию в XAML. List<T> реализует интерфейс IList, поэтому он компилируется так, как вы ожидаете.

Если AdvisableCollection<T> реализует IList, вы можете просто использовать IList, что может быть нежелательно, поскольку вы теряете строго типизированный интерфейс.

Если AdvisableCollection<T> реализует довольно универсальный тип коллекции, такой как System.Collections.Generic.List<T> или System.Collections.ObjectModel.Collection<T>, вы можете использовать эти типы для определения. Хотя они и не такие общие, но все же довольно универсальные, и эти типы имеют ограниченное количество дополнительных свойств и методов, которые делают переход между типами IList<T> довольно простым и понятным.

Другой возможный вариант — реализация класса-оболочки, который наследует интерфейсы IList и IList<T>. Это дает возможность работать с любым конкретным типом, который реализует IList<T>, имея при этом строго типизированную коллекцию.

person Dru Bradley    schedule 27.04.2020