Включение прямого создания контента в XAML на объекте зависимости - PullRequest
4 голосов
/ 08 июля 2009

У меня есть класс CollectionOfThings. Как следует из названия, это простая коллекция экземпляров класса Thing. Класс Thing имеет общедоступный конструктор по умолчанию и два простых общедоступных get, устанавливают свойства ID и DisplayName, оба являются строковыми. CollectionOfThing также имеет открытый конструктор по умолчанию.

В XAML я хотел бы использовать разметку следующим образом: -

<Grid.Resources>
    <local:CollectionOfThings x:Key="Things">
        <local:Thing ID="1" DisplayName="Hello" />
        <local:Thing ID="2" DisplayName="World" />
    <local:CollectionOfThings>
</Grid.Resources>

Все хорошо, пока CollectionOfThings наследуется от типа Collection. Однако я хочу, чтобы CollectionOfThings также был DependencyObject. Я думал, что это хорошо, создать реализацию ICollection<T>, INotifyCollectionChanged и т. Д. Не так сложно. Тогда я могу извлечь из DependencyObject.

К сожалению ICollection<T> по какой-то причине не сокращает его. С ICollection<Thing> я получаю «CollectionOfThings не поддерживает Thing как контент». Вернитесь к Collection<Thing> и все работает, но оставляет меня без DependencyObject реализации.

Предложения кого-нибудь?

Ответы [ 2 ]

7 голосов
/ 09 июля 2009

XAML хочет System.Collections.IList (неуниверсальный!) Для коллекций. Если вы реализуете только общий интерфейс IList<T>, он не будет сокращен.

Он также ожидает увидеть открытые Add методы в классе и извлекает подходящие дочерние типы для коллекции из аргументов этих методов. Таким образом, типичный подход заключается в явной реализации IList - так, чтобы его метод Add(object) не был общедоступным и, следовательно, не выбирался синтаксическим анализатором XAML, - а затем неявно реализовывал IList<T> для всех дочерних типов, которые вы хотите поддерживать .

Причина, по которой он работает для большинства встроенных типов коллекций (List<T>, Collection<T> и т. Д.), Заключается в том, что они следуют приведенному выше шаблону и реализуют как универсальные, так и неуниверсальные интерфейсы.

5 голосов
/ 09 июля 2009

Коллекции обычно используются в xaml для определения ContentPropertyAttribute("PropertyName") в пользовательском классе, где PropertyName обычно IList или IList<T>.

[ContentProperty(SomeProp)]
class SomeClass
{
    //this is where subitems created in xaml would get added automatically
    public IList<int> SomeProp { get; set; } 
}

Однако, если класс не предоставляет значение для ContentPropertyAttribute и реализует какой-либо интерфейс типа IList<T>, IList, ICollection<T> или ICollection, свойство с именем «Items» (если присутствует, и если соответствующего типа, например, IList), автоматически определяется через отражение (с целью заполнения через xaml), и это имеет место с классом Collection<T>.

Вы даже можете проверить класс в Reflector, чтобы убедиться, что у него не определено свойство содержимого.

Класс Collection<T> обладает этим свойством

protected IList<T> Items
{
    get
    {
        return _items;
    }
}

и добавления чего-то подобного к типу вашей коллекции (даже если свойство защищено) достаточно, чтобы оно работало в xaml так, как требуется.

Я полагаю, что поведение реализовано таким образом для обратной совместимости.

...