【问题标题】:Multiple instances of user control with a canvas causes exception in Silverlight带有画布的用户控件的多个实例导致 Silverlight 中的异常
【发布时间】:2010-07-17 14:10:00
【问题描述】:

我有一个用户控件,它有一个网格(您在创建用户控件时自动获得的那个)和其中的一个画布。

<Grid x:Name="LayoutRoot" Background="White">
    <Canvas x:Name="SurfaceCanvas">
    </Canvas>
</Grid>

在 CS 文件中,我定义了一个“Items”集合。

public ObservableCollection<TestItem> Items {
    get { return (ObservableCollection<TestItem>)GetValue(ItemsProperty); }
    set { SetValue(ItemsProperty, value); }
}

public static readonly DependencyProperty ItemsProperty =
    DependencyProperty.Register("Items", typeof(ObservableCollection<TestItem>),
    typeof(TestControl),
    new PropertyMetadata(new ObservableCollection<TestItem>()));

TestItem 类声明:

public class TestItem : ContentControl { ... }

通过 XAML 添加项目。

<my:TestControl x:Name="ControlOne" Height="100" Width="100">
    <my:TestControl.Items>
        <my:TestItem x:Name="ItemOne">One</my:TestItem>
    </my:TestControl.Items>
</my:TestControl>

<my:TestControl x:Name="ControlTwo" Height="100" Width="100">
    <my:TestControl.Items>
        <my:TestItem x:Name="ItemTwo">Two</my:TestItem>
    </my:TestControl.Items>
</my:TestControl>

当项目被添加到集合中时,我将它们添加到画布中。

void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
    switch(e.Action) {
        case NotifyCollectionChangedAction.Add:
            foreach(Control item in e.NewItems) {
                SurfaceCanvas.Children.Add(item);
            }
        break;
    }
}

现在,问题来了。

如果此控件有一个实例,则一切正常。但是当我定义第二个实例时,我在添加到ControlTwo 的项目上收到InvalidOperationException:“元素已经是另一个元素的子元素”。

当我逐步查看元素被添加到画布时,发生的情况是它创建 ItemOne 并将其添加到 ControlOne,然后创建 ItemTwo 并将其添加到 ControlOne,然后再尝试添加发给ControlTwo。这会导致异常,因为您不能同时将一个元素作为两个控件的父级。

我的猜测是它与每个实例中的画布具有相同名称的事实有关,因此当它解析“SurfaceCanvas”时,它会返回两个实例并按顺序添加到每个实例中。这只是基于观察的猜测。

我做错了什么?

【问题讨论】:

    标签: c# wpf silverlight xaml user-controls


    【解决方案1】:

    花了我一分钟,但这很棘手:

    您的 DependencyProperty 有一个默认值。默认值只为您的 DependencyProperty 创建一次,然后分配给您的 TestControl 的两个实例。这样,当您向 TestControl.Items 添加一些内容时,您会将其添加到公共 ObservbleCollection,它现在有两个 CollectionChanged 事件委托,每个委托都将新项目添加到各自的 Canvas。

    删除 ItemsProperty 的默认值。在构造函数中创建一个 ObservbleCollection,或者 xaml 解释器将为每个 TestControl 创建一个。

    规则:DependencyProperty 的默认值仅用于值类型,而不是引用类型。

    【讨论】:

    • 感谢您让我更上一层楼。
    • +1,对于所有具有引用类型的 DependencyProperties,这是一个经典的陷阱。但是,我会稍微放宽规则以“仅将默认值用于值类型 用于对不可变对象的引用”。 “不可变”的一个很好的例子是String
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    相关资源
    最近更新 更多