【问题标题】:Initializing an ICollection within XAML在 XAML 中初始化 ICollection
【发布时间】:2011-06-20 17:37:44
【问题描述】:

尝试做这样的事情......

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>

【问题讨论】:

  • 替换公共 ICollection 内容 { get; set;} 与 public List Content { get; set;} 有效,但我需要避免使用实际的实现。使用 IList 会导致同样的错误。
  • 如果您不使用实际实现,您将如何用数据填充集合?
  • @John Gardner 我选择 ICollection 的原因是因为 MiniObject 在 ORM 中使用,我希望它只使用 IList 或 ICollection 等接口。我在这里编写的代码用于设计时数据和测试。我不想为了让设计师开心而单独编写一个类。

标签: c# wpf xaml collections


【解决方案1】:

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

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

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

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

【讨论】:

  • MSDN,要在XAML中声明一个集合属性,集合类型可以是IListIDictionaryArray之一或实现IAddChild,但你的答案听起来好像ICollection 没问题。
  • 啊,好吧,我想我明白了,这是有道理的,因为它不知道要实现哪种类型的 ICollection。现在我只需要弄清楚如何执行我在第二个示例中解释的内容。谢谢。
【解决方案2】:

仅使用上面提到的代码,由于MSDN

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) 中,您可能知道 XAML 中的集合属性有四种选择(IList、IDictionary 等)。请参考MSDN。上面,ICollection 也是可以的,因为项目被添加到了 ArrayList 中。

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

【讨论】:

  • 非常有趣,值得了解。我没有将它作为答案投票,主要是因为它不适合我当前的实现,我需要一组已知类型(我在树视图中访问 UI 中对象的一些变量)。我认为当实现通用类型集合时这将是一个有用的功能,但目前我认为它比简单地要求设计时/ window.resources 实例化的包装器更令人困惑。
【解决方案3】:

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

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

这对我有用。 此外,如果您使用 IEnumerable 而不是 IList,则会产生构建错误。

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

【讨论】:

    猜你喜欢
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多