2009-07-08 16 views
4

J'ai une classe CollectionOfThings. Comme son nom l'indique, il s'agit d'une simple collection d'instances de la classe Thing. Thing classe a un constructeur public par défaut et deux get public simple, définir les propriétés ID et DisplayName, les deux sont chaîne. CollectionOfThing possède également un constructeur par défaut public.Activation de la création de contenu direct en XAML sur un objet de dépendance

Dans XAML Je voudrais utiliser le balisage comme ceci: -

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

Tout est bon aussi longtemps que CollectionOfThings dérive d'un type de collection. Cependant, je veux CollectionOfThings également être un DependencyObject. Je pensais que c'est bien de créer une implémentation de ICollection<T>, INotifyCollectionChanged etc n'est pas si difficile. Ensuite, je peux dériver de DependencyObject.

Malheureusement, ICollection<T> ne le coupe pas pour une raison quelconque. Avec ICollection<Thing> je reçois 'CollectionOfThings ne supporte pas Thing comme contenu'. Retour à Collection<Thing> et tout fonctionne mais me laisse sans une implémentation DependencyObject.

Suggestions personnes? sont généralement utilisés

Répondre

7

XAML veut System.Collections.IList (le non-générique!) Pour les collections. Si vous ne mettez en œuvre l'interface générique IList<T>, il ne sera pas coupé.

Il s'attend également à voir les méthodes publiques Add sur la classe, et dérive les types enfants appropriés pour la collection à partir des arguments de ces méthodes. L'approche typique consiste donc à implémenter explicitement IList - de sorte que sa méthode Add(object) ne soit pas publique, et ne soit donc pas sélectionnée par l'analyseur XAML - puis implémente implicitement IList<T> pour tous les types enfants que vous voulez prendre en charge.

La raison pour laquelle cela fonctionne pour la plupart des types de collection intégrés (List<T>, Collection<T> etc.) est qu'ils suivent le modèle ci-dessus et implémentent des interfaces génériques et non génériques.

+0

C'est ce que j'ai compris! La vanilla IList était ce qui me manquait, merci. – AnthonyWJones

+0

Réponse parfaite, je pensais utiliser IList pensant qu'il serait préférable de Liste , maintenant grâce à ce poste, je sais pourquoi et je suis heureux avec l'utilisation de la liste comme le type de propriété. Je reçois le support de design qui me manquait avec IList –

5

Collections en XAML de manière à définir un ContentPropertyAttribute("PropertyName") sur la classe personnalisée où PropertyName est généralement IList ou IList<T>.

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

Cependant, si une classe ne fournit pas de valeur pour l'ContentPropertyAttribute, et met en œuvre toute interface de type IList<T>, IList, ICollection<T> ou ICollection, une propriété du nom « Items » (le cas échéant, et si des appropriés type, par exemple IList) est détectée automatiquement par réflexion (pour les besoins de la population xaml), et c'est le cas avec la classe Collection<T>.

Vous pouvez même vérifier la classe dans Reflector pour vous assurer qu'aucune propriété de contenu n'a été définie.

La classe Collection<T> a cette propriété

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

et en ajoutant quelque chose comme ça à votre type de collection (même si la propriété est protégée) est suffisante pour avoir voulu se comporter comme en XAML.

Je suppose que le comportement est implémenté de cette manière pour des raisons de compatibilité ascendante.

+0

@ kky444: Merci pour la réponse. Cependant, comme je l'ai dit dans ma question, je suis déjà en train d'implémenter ICollection , mais cela ne semble pas encore aider. J'ai également essayé d'implémenter IList et d'exposer une propriété Items avec un attribut ContentProperty décorant la classe. Rien de tout cela ne fonctionne. (BTW IList est un ICollection pas l'inverse). – AnthonyWJones

+0

@AnthonyWJones: d'accord, pour résumer, ne pas définir la propriété de contenu, utilisez IList , exposer une propriété Items de type IList , et cela fonctionnera, je viens de le vérifier. L'éditeur de xaml peut argumenter, c'est vrai, mais il va construire. –

+0

@ kky444: +1 merci je le sais maintenant. – AnthonyWJones