Enabling Direct Content Creation in XAML for a Dependency Object

I have a CollectionOfThings class. As its name suggests, its simple collection of Thing class instances. Thing class has an open default constructor and two simple public get, sets the ID and DisplayName properties, both are strings. CollectionOfThing also has an open default constructor.

In XAML, I would like to use markup as follows: -

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

All is well if CollectionOfThings comes from a Collection type. However, I want CollectionOfThings also be a DependencyObject . I thought it was a great creation implementation of ICollection<T> , INotifyCollectionChanged , etc. Not so difficult. Then I can get from DependencyObject .

Unfortunately, ICollection<T> for some reason does not cut. With ICollection<Thing> I get: "CollectionOfThings does not support Thing as content." Go back to Collection<Thing> , and everything works, but leaves me without a DependencyObject implementation.

Anyone suggestions?

+4
source share
2 answers

XAML wants System.Collections.IList (not generic)! for collections. If you implement only the common IList<T> interface, it will not crop it.

He also expects to see the public Add methods in the class and infers the appropriate child types for the collection from the arguments of these methods. Thus, a typical approach is to explicitly implement IList so that its Add(object) method is not public and therefore not selected by the XAML parser, and then implicitly implements IList<T> for all child types that you want to support .

The reason it works for most of the built-in collection types ( List<T> , Collection<T> , etc.) is because they follow the pattern above and implement both common and non-common interfaces.

+7
source

Collections are commonly used in ContentPropertyAttribute("PropertyName") to define a ContentPropertyAttribute("PropertyName") in a custom class, where the PropertyName usually IList or IList<T> .

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

However, if the class does not provide a value for ContentPropertyAttribute and implements any interface of type IList<T> , IList , ICollection<T> or ICollection , the property of the name "Items" (if present, and if the corresponding type, for example IList ), is automatically detected through reflection (for population purposes via xaml), and this is the case with the Collection<T> class.

You can even check the class in Reflector to make sure it does not have a content property.

Collection<T> class has this property

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

and adding something similar to your collection type (even if this property is protected) is enough for it to behave as desired in xaml.

I believe that the behavior is implemented this way for backward compatibility.

+5
source

All Articles