在 XAML 中对依赖对象启用直接内容创建
我有一个类CollectionOfThings
。 顾名思义,它是 Thing
类实例的简单集合。 Thing
类有一个公共默认构造函数和两个简单的公共 get、set 属性 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
、INotifyCollectionChanged
等的实现并不难。 然后我可以从 DependencyObject
派生。
不幸的是,由于某种原因,ICollection
并没有削减它。 使用 ICollection
我得到“CollectionOfThings 不支持 Thing 作为内容”。 返回到 Collection
,一切正常,但我没有 DependencyObject
实现。
有人建议吗?
I have a class CollectionOfThings
. As its name suggests its a simple collection of instances of the Thing
class. Thing
class has a public default constructor and two simple public get, set properties ID
and DisplayName
, both are string. CollectionOfThing
also has public default constructor.
In XAML I would like to use markup like this:-
<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 good as long as CollectionOfThings derives from a Collection type. However I want CollectionOfThings
to also be a DependencyObject
. I thought that's fine creating an implementation of ICollection<T>
, INotifyCollectionChanged
etc is not that hard. Then I can derive from DependencyObject
.
Unfortunately ICollection<T>
doesn't cut it for some reason. 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.
Suggestions anyone?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
XAML 需要
System.Collections.IList
(非泛型!)作为集合。 如果您只实现通用的IList
接口,它不会削减它。它还期望在类上看到公共
Add
方法,并从这些方法的参数中派生出适合集合的子类型。 因此,典型的方法是显式实现IList
- 以便其Add(object)
方法不是公共的,因此不会被 XAML 解析器选择 - 然后隐式实现为您想要支持的所有子类型实现IList
。它适用于大多数内置集合类型(
List
、Collection
等)的原因是因为它们遵循上述模式并实现了通用和非通用接口。XAML wants
System.Collections.IList
(the non-generic one!) for collections. If you only implement genericIList<T>
interface, it won't cut it.It also expects to see public
Add
methods on the class, and derives suitable child types for the collection from arguments of those methods. So the typical approach is to explicitly implementIList
- so that itsAdd(object)
method isn't public, and thus isn't picked by XAML parser - and then implicitly implementIList<T>
for all child types that you want to support.The reason why it works for most built-in collection types (
List<T>
,Collection<T>
etc) is because they follow the pattern above and implement both generic and non-generic interfaces.集合通常在 xaml 中使用,以便在自定义类上定义
ContentPropertyAttribute("PropertyName")
,其中PropertyName
通常是IList
或IList
。但是,如果类没有为
ContentPropertyAttribute
提供值,并且实现了IList
、IList
、类型的任何接口>ICollection
或ICollection
,通过反射检测名称为“Items”的属性(如果存在,并且类型适当,例如IList
)自动(为了通过 xaml 进行填充),Collection
类就是这种情况。您甚至可以检查 Reflector 中的类,以确保它没有定义内容属性。
Collection
类具有此属性,并且向您的集合类型添加类似的内容(即使该属性受保护)就足以使其在 xaml 中按照所需的方式运行。
我想这种行为是为了向后兼容而实现的。
Collections are usually used in xaml so as to define a
ContentPropertyAttribute("PropertyName")
on the custom class wherePropertyName
is usuallyIList
orIList<T>
.However, if a class does not provide a value for the
ContentPropertyAttribute
, and implements any interface of typeIList<T>
,IList
,ICollection<T>
orICollection
, a property of name "Items" (if present, and if of appropriate type, e.g.IList
) is detected trough reflection automatically (for the purpose of population trough xaml), and that is the case with theCollection<T>
class.You can even check the class in Reflector to make sure it has no content property defined.
The
Collection<T>
class has this propertyand adding something like that to your collection type (even if the property is protected) is enough to have it behave as desired in xaml.
I suppose the behavior is implemented in that way for backward compatibility.