c# - Silverlight 嵌套自定义控件导致 StackOverflowException

标签 c# xaml silverlight controls stack-overflow

我正在为我的 Silverlight 项目编写一个可重用的 Controllibrary。目前我每次启动我的测试应用程序时都会收到一个 StackOverflowException,它正在使用 Controllibrary。我能够在一个小样本 Projekt 中重现异常。

我有两个简单的自定义控件:

//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。在我的 Controllibrary 中,Control1 与 MenuItem 类似,当按下 Control2 时,MenuItem 会传递给菜单。 现在在我的 Themes/generic.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 加载其样式时,一切都可以正常加载。但这更像是一种解决方法而不是解决方案。

当我在 generic.xaml 中删除我的 TestProperty 的 Setter 时,一切正常。然后我能够覆盖测试应用程序的 App.xaml 中的样式,并在那里为 TestProperty 定义 setter 。但这也不是我想做的。

有人对此问题有解决方案吗? 或者也许有人可以向我解释为什么它会这样。

提前致谢

最佳答案

我自己偶然发现了这种出色的效果,结果是:

您不能实例化从 UIElement 派生的对象(你的行 <local:Control1/> 正是这样尝试的)在 ResourceDictionary 中(generic.xaml 是其中之一),因为所述字典中的所有对象都必须是可共享的。

已记录 here .相关部分:

Shareable Types and UIElement Types

A resource dictionary is a technique for defining shareable types and values of these types in XAML. Not all types or values are suitable for usage from a ResourceDictionary. For more information on which types are considered shareable in Silverlight, see Resource Dictionaries.

In particular, all UIElement derived types are not shareable unless they come from templates and application of a template on a specific control instance. Excluding the template case, a UIElement is expected to only exist in one place in an object tree once instantiated, and having a UIElement be shareable would potentially violate this principle.

但有治愈方法

将您的 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 ) );
}

关于c# - Silverlight 嵌套自定义控件导致 StackOverflowException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30737916/

相关文章:

visual-studio-2010 - Silverlight 4 : Resolving Microsoft. Silverlight.CSharp.targets 未找到?

c# - 更改 ConcurrentBag 中的对象?

c# - 在运行时创建委托(delegate)类型

wpf - 菜单中菜单项前后的空格

c# - MS 出版商自动化

silverlight - 遵循 MVVM 模式动态创建控件

c# - 重复播放列表中的单首歌曲

c# - 多维数组列排序

xaml - 有没有办法让我的 BackgroundImage 均匀地填充 ContentPage? Xamarin.Forms,XAML

xaml - 在 xaml 中使用自定义字体