C# 初始化XAML中的ICollection

C# 初始化XAML中的ICollection,c#,wpf,xaml,collections,C#,Wpf,Xaml,Collections,试图做这样的事情 public class MiniObject { public bool Checked { get; set; } public String Caption { get; set; } public ICollection<MiniObject> Content { get; set;} } <Window.Resources> <local:MiniObject x:Key="RootItem" Cap

试图做这样的事情

public class MiniObject
{
    public bool Checked { get; set; }
    public String Caption { get; set; }

    public ICollection<MiniObject> Content { get; set;}
}


<Window.Resources>
    <local:MiniObject x:Key="RootItem" Caption="Item0" Checked="True">
        <local:MiniObject.Content>
            <local:MiniObject Caption="Item1" Checked="True">
            </local:MiniObject>
            <local:MiniObject Caption="Item2" Checked="True">
            </local:MiniObject>
        </local:MiniObject.Content>
    </local:MiniObject>
</Window.Resources>
在WPF中是否有这样做的方法?如果是这样的话,我是否需要改变我的对象的形状,或者我可以简单地提供一个只有WPF使用的特殊对象,比如

<Window.Resources>
    <local:MiniObject x:Key="RootItem" Caption="Item0" Checked="True">
        <local:MiniObject.Content>
            <local:MiniObjectCollection>
                <local:MiniObject Caption="Item1" Checked="True">
                </local:MiniObject>
                <local:MiniObject Caption="Item2" Checked="True">
                </local:MiniObject>
            </local:MiniObjectCollection>
        </local:MiniObject.Content>
    </local:MiniObject>
</Window.Resources>

您正在尝试使用XAML的隐式集合语法。为此,属性(
Content
,在本例中)必须是实现
ICollection
的类型。注意:不是
ICollection
,而是实现
ICollection
的类型

不能只使用接口,因为
XamlReader
需要知道要创建什么类型的对象。如果你没有告诉它类型,它应该如何决定?通过搜索程序集可用的所有类型,查找实现ICollection的类型,丢弃没有无参数构造函数的类型,然后随机选择一个?没有

当您将
Content
定义为
List
时,
XamlReader
知道它应该创建什么类型的对象。由于该类型实现了
ICollection
,因此可以使用隐式集合语法。因此,它只是创建对象并调用
Add
来添加子项,如果您在其中插入了一个不是
MiniObject
的子项,则会出现运行时错误


您在
Content
属性中说“我需要避免使用实际实现”。在这种情况下,不能使用隐式集合语法。您将需要执行第二个示例中的操作:显式定义一个实现
ICollection
的类型,并在XAML中添加一个子元素以显式创建它。

仅使用上面提到的代码,在XAML中编写集合属性时将作为空引用异常抛出,原因是:

因此,如果您不想在类声明中包含集合实例,我建议按如下方式在XAML中初始化集合

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System.Collections;assembly=mscorlib"  xmlns:local="clr-namespace:WpfApplication1"  Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:MiniObject x:Key="RootItem" Caption="Item0" Checked="True">
            <local:MiniObject.Content>
                <system:ArrayList>  -------------------------------------1)
                    <local:MiniObject Caption="Item1" Checked="True">
                    </local:MiniObject>
                    <local:MiniObject Caption="Item2" Checked="True">
                    </local:MiniObject>
                </system:ArrayList>
            </local:MiniObject.Content>
        </local:MiniObject>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Source={StaticResource ResourceKey=RootItem}, Path=Content}" DisplayMemberPath="Caption"/>
    </Grid>
</Window>


public class MiniObject
{
    public bool Checked { get; set; }
    public String Caption { get; set; }

    public IList Content { get; set; } -----------------------------------------2)
}

-------------------------------------1)
公共类小型对象
{
公共布尔检查{get;set;}
公共字符串标题{get;set;}
公共IList内容{get;set;}------------------------------------------2)
}
在第二部分中,您可能知道XAML中有四个可选的集合属性(IList、IDictionary等)。请参阅。如上所述,ICollection也可以,因为项目已添加到ArrayList


在1)中,我们还不能声明泛型类型集合,但我知道它将尽快得到支持。

我也有类似的要求,并以与@NtscCobalt相同的方式实现,并得到相同的异常

此异常的一个简单解决方案是使用某个集合List或OvservableCollection初始化Content属性

这对我有用。 此外,如果使用IEnumerable而不是IList,则会出现生成错误

private IList<MiniObject> _content = new List<MiniObject>();
public IList<MiniObject> Content 
{ 
    get
    {
        return _content;
    } 
    set
    {
        _content=value;
    }
}
private IList_content=new List();
公共IList内容
{ 
得到
{
返回内容;
} 
设置
{
_内容=价值;
}
}

用公共列表内容{get;set;}替换公共ICollection内容{get;set;}是可行的,但我需要避免使用实际的实现。使用IList也会导致同样的错误。如果不使用实际的实现,如何用数据填充集合?@John Gardner我选择ICollection的原因是因为MiniObject用于ORM,我希望它只使用IList或ICollection这样的接口。我在这里写的代码是用于设计时数据和测试的。我不希望编写一个单独的类只是为了让设计者高兴。从中,要在XAML中声明集合属性,集合类型可以是
IList
IDictionary
Array
或实现
IAddChild
,但是你的回答听起来好像
ICollection
是可以的。啊,好吧,我想我理解了,这是有道理的,因为它不知道要实现什么类型的ICollection。现在我只需要弄清楚如何做我在第二个例子中解释的事情。谢谢。很有趣,很高兴知道。我不把它作为答案,主要是因为它不适合我当前的实现,我需要一个已知类型的集合(我在树视图中访问UI中对象的一些变量)。我认为在实现泛型类型集合时,这将是一个有用的特性,但目前我认为这比简单地要求为设计时/window.resources实例化使用包装器更令人困惑。
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:system="clr-namespace:System.Collections;assembly=mscorlib"  xmlns:local="clr-namespace:WpfApplication1"  Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:MiniObject x:Key="RootItem" Caption="Item0" Checked="True">
            <local:MiniObject.Content>
                <system:ArrayList>  -------------------------------------1)
                    <local:MiniObject Caption="Item1" Checked="True">
                    </local:MiniObject>
                    <local:MiniObject Caption="Item2" Checked="True">
                    </local:MiniObject>
                </system:ArrayList>
            </local:MiniObject.Content>
        </local:MiniObject>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Source={StaticResource ResourceKey=RootItem}, Path=Content}" DisplayMemberPath="Caption"/>
    </Grid>
</Window>


public class MiniObject
{
    public bool Checked { get; set; }
    public String Caption { get; set; }

    public IList Content { get; set; } -----------------------------------------2)
}
private IList<MiniObject> _content = new List<MiniObject>();
public IList<MiniObject> Content 
{ 
    get
    {
        return _content;
    } 
    set
    {
        _content=value;
    }
}