Silverlight嵌套自定义控件导致StackOverflowException

本文关键字:StackOverflowException 自定义控件 嵌套 Silverlight | 更新日期: 2023-09-27 17:54:33

我正在为我的Silverlight项目编写一个可重用的控制库。目前我得到一个StackOverflowException每次我启动我的测试应用程序,这是使用控制库。我能够在一个小样本项目中重现异常。

我有两个简单的自定义控件:
//Control1.cs
public class Control1:Control
{
    public Control1()
    {
        this.DefaultStyleKey = typeof(Control1);
    }
}
//Control2.cs
public class Control2:Control
{
    public static DependencyProperty TestProperty =  
            DependencyProperty.Register("Test",typeof(Control1),typeof(Control2),null);
    public Control1 Test
    {
        get {return (Control1)GetValue(TestProperty);}
        set {SetValue(TestProperty,value);}
    }
    public Control2()
    {
        this.DefaultStyleKey = typeof(Control2);
    }
}

Constrol2有一个Control1类型的DependencyProperty。在我的控制库中,Control1类似于按下Control2时传递给菜单的MenuItem。现在在我的主题/通用。xaml定义了控件的两个默认样式:

//generic.xaml
<Style TargetType="local:Control1">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:Control1">
                <Rectangle Width="20" Height="20" Fill="Blue"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<Style TargetType="local:Control2">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:Control2">
                <Rectangle Width="20" Height="20" Fill="Red"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Test">
        <Setter.Value>
            <local:Control1/>
        </Setter.Value>
    </Setter>
</Style>

现在当我在测试应用程序中使用Control2时,我得到一个StackOverflowException。设置断点时,Control2的构造函数被调用一次,然后Control1的构造函数被连续调用,直到StackOverflowException。

当我改变control1的构造函数直接从一个resourceKey的ResourceDictionary加载它的样式时,一切都加载得很好。但这更像是一种变通而不是解决方案。

当我在泛型中删除TestProperty的Setter时。Xaml一切都很好。然后我就可以在测试应用程序的App.xaml中重写样式,并在那里为TestProperty定义Setter。但那也不是我想做的。

谁有解决这个问题的办法?或者也许有人能解释一下为什么它会这样。

Thanks in advance

Silverlight嵌套自定义控件导致StackOverflowException

我自己偶然发现了这个绝妙的效果,结果是:

你不能实例化从UIElement派生的对象(你的<local:Control1/>行正是这样做的)在ResourceDictionary(和泛型)。Xaml是一个),因为该字典中的所有对象必须是可共享的。

记录在这里。相关部门:

可共享类型和元素类型

资源字典是一种定义可共享类型的技术这些类型的值在XAML中。并非所有类型或值都适合以获取资源词典中的用法。想了解更多信息类型在Silverlight中被认为是可共享的,参见参考资料字典。

特别地,所有元素派生类型都是不可共享的,除非它们来自于模板和特定模板上的应用控制实例。除了模板之外,还需要一个UIElement在实例化后仅存在于对象树中的一个位置,并且让一个元素是可共享的可能会违反这一点原则。

将您的control1包装在DataTemplate中,导致您的control1不在ResourceDictionary中实例化,而是在实际实例化control2的时间点。

<Style TargetType="OuterControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="OuterControl">
                <StackPanel>
                    <TextBlock Text="Outer Hello World"/>
                    <ContentPresenter
                        Content="{TemplateBinding Content}"
                        ContentTemplate="{TemplateBinding ContentTemplate}"/>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <InnerControl/>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

和代码

public class OuterControl : Control
{
    public OuterControl()
    {
        DefaultStyleKey = typeof( OuterControl );
    }
    public InnerControl Content
    {
        get { return (InnerControl) GetValue( ContentProperty ); }
        set { SetValue( ContentProperty, value ); }
    }
    public static readonly DependencyProperty ContentProperty =
        DependencyProperty.Register( "Content", typeof( InnerControl ), typeof( OuterControl ), new PropertyMetadata( null ) );
    public DataTemplate ContentTemplate
    {
        get { return (DataTemplate) GetValue( ContentTemplateProperty ); }
        set { SetValue( ContentTemplateProperty, value ); }
    }
    public static readonly DependencyProperty ContentTemplateProperty =
        DependencyProperty.Register( "ContentTemplate", typeof( DataTemplate ), typeof( OuterControl ), new PropertyMetadata( null ) );
}

相关文章:
  • 没有找到相关文章