在XAML中初始化ICollection

时间:2011-06-20 17:37:44

标签: 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" 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>

这当然无法返回错误:

Object of type 'WorkflowTest.MiniObject' cannot be converted to type 'System.Collections.Generic.ICollection`1[WorkflowTest.MiniObject]'.

有没有办法在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>

3 个答案:

答案 0 :(得分:1)

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

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

Content定义为List<MiniObject>时,XamlReader知道应该创建的对象类型。由于这是一种实现ICollection的类型,因此它可以使用隐式集合语法。所以它只是创建对象并调用Add来添加子项,如果你在那里放了一个不是MiniObject的子项,你就会遇到运行时错误。

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

答案 1 :(得分:1)

仅使用上面提到的代码,由于来自MSDN的事实,它将作为空引用异常抛出,以在XAML中编写集合属性:

The presence of that collection type is implicit whenever you specify a property 
in XAML that takes a collection type.

因此,如果您不希望在类声明中拥有集合实例,我建议在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)
}

在2),你可能知道有四种选择(IList,IDictionary等)作为XAML中的集合属性。请参阅MSDN。上面,ICollection也可以,因为这些项被添加到ArrayList。

在1),我们还不能声明一个泛型类型集合,但我知道它会很快得到支持。

答案 2 :(得分:0)

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

此异常的一个简单解决方案是使用List&lt;&gt;的一些集合初始化Content属性。或OvservableCollection&lt;&gt;。

这对我有用。 此外,如果您使用IEnumerable而不是IList,它将给出构建错误。

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