UserControl.InitializeComponent()中的间歇性InavlidCastException

时间:2009-01-22 21:45:38

标签: silverlight silverlight-2.0

以下是设置:

我有一个Silverlight控件库“Controls”,我在其中定义了一个用于显示对话框的客户控件:

public class Dialog : ContentControl
{
    public Dialog()
        : base()
    {
        DefaultStyleKey = typeof(Dialog);
    }

<...normal custom control stuff...>
}

默认样式也在generic.xaml中:

<Style TargetType="src_general:Dialog">
    <Setter Property="Padding" Value="25"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="src_general:Dialog">
                <Grid x:Name="RootElement" >
                    <vsm:VisualStateManager.VisualStateGroups>
                        <vsm:VisualStateGroup x:Name="DiakogStyleStates">
                            <vsm:VisualState x:Name="OkCancel">
                                <Storyboard>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="OkOnly">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="CancelButton" Storyboard.TargetProperty="Visibility" >
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="CancelOnly">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="OkButton" Storyboard.TargetProperty="Visibility" >
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                            <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="None">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="CancelButton" Storyboard.TargetProperty="Visibility" >
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                         <ObjectAnimationUsingKeyFrames Duration="0:0:0" Storyboard.TargetName="OkButton" Storyboard.TargetProperty="Visibility" >
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                            <DiscreteObjectKeyFrame.Value>
                                                    <Visibility>Collapsed</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </vsm:VisualState>
                        </vsm:VisualStateGroup>
                    </vsm:VisualStateManager.VisualStateGroups>
                         <Popup x:Name="DialogPopup">
                        <src_general:WindowFrame x:Name="Frame">
                            <Grid >
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="Auto" />
                                </Grid.RowDefinitions>

                                <ContentPresenter Grid.Row="0" x:Name="ContentPresenter" Margin="{TemplateBinding Padding}"/>
                                     <!--Action Buttons-->
                                <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="15">
                                    <src_general:GlassButton x:Name="CancelButton" Content="Cancel" Margin="2"/>
                                    <src_general:GlassButton x:Name="OkButton" Content="Ok" Margin="2"/>
                                </StackPanel>
                            </Grid>

                        </src_general:WindowFrame>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我在很多地方使用此对话框没有问题。但是,在一个应用程序中,嵌套了来自RootVisual的大约3-4个用户控件,我使用它以下方式:

<general:Dialog x:Name="AddUpdateDialog" DialogStyle="OkCancel" Title="Add/Update Connection" Closed="AddUpdateDialog_Closed" ValidationGroup="AddConnection">
            <Grid Width="300">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="10"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>

                <TextBlock Grid.Row="0" Grid.Column="0" Text="Name:" Style="{StaticResource LabelText}"/>
                <TextBox Grid.Row="0" Grid.Column="2" Text="{Binding Name, Mode=TwoWay}" Style="{StaticResource TextBoxInput}" MaxLength="49">
                    <val:ValidationManager.Validator>
                        <val:RequiredValidator ManagerName="AddConnection" ErrorMessage="Name is required."/>
                    </val:ValidationManager.Validator>
                </TextBox>
            </Grid>
        </general:Dialog>

当我间歇性地运行这个应用程序时(大约每5-10次启动会得到以下异常:

“无法将System.Windows.Controls.ContentControl类型的对象转换为hookitupright.com.silverlight.controls.general.Dialog类型。”发生在上述XAML的父InitializeComponent()的{​​{1}}中。

具体而言,它就在这里:

UserControl

当我在那里放置一个断点时,大多数时候FindName返回一个Dialog类型的对象,但有时,它返回一个ContentControl(Dialog的基础),它失败了。 XAML没有改变。它是静态的......由于异常是间歇性的并且在生成的代码中发生,我感到茫然。

我试过了:

  1. 将Dialog的所有内容移动到单独的UserControl中 - 似乎只会让问题变得更糟
  2. 注释掉部分并查看它的工作原理......好吧,如果我完全注释掉TextBox,它就不会再失败了。其他一切(包括自定义验证附加属性)似乎没有任何影响。

    2a上。认为它可能与TwoWay绑定到TextBox有关,我删除了绑定。仍然失败。

  3. 更新:所以上面给出的(2)我留下了文本框注释掉决定继续其他事情并回到这一点,希望有些东西会向我揭示。不幸的是,似乎也失败了Textbox,只是不那么频繁。

    此外,我在同一个应用程序中的另一个用户控件(并且在VisualTree中的同一级别)中具有完全相同的配置,并且它根本不会失败。因此,我将失败的XAML复制并粘贴到Main.xaml(我的根视觉)中,当然,它也不会失败。假设XAML按顺序加载(从上到下),失败的控件可能是最后加载的控件之一。我现在唯一的假设就是发生了一些时间问题,因为当我仍在加载可视化树时,我开始从通过WCF服务加载数据获得*已完成事件,并且这些事件在可视化树之前触发布局满载会导致一些不良副作用......我会测试一下。

    问题是每次都不会失败。它爆炸了大约20%的时间。当它工作时,一切都可以用于对话吗?

    如果不是同一个问题,这个问题是相关的:当我通过注释掉所需的功能来“修复”无效广播时,我会不那么频繁但间歇性地获得this无效属性(当属性/属性实际上是有)。

2 个答案:

答案 0 :(得分:1)

经过多次研究和挫折之后,我认为这与此有关:http://blogs.msdn.com/silverlight_sdk/archive/2008/10/24/loaded-event-timing-in-silverlight.aspx

Silverlight中的Loaded事件与(a)WPF中的内容不一致,因此(b)它们从WPF粘贴到Silverlight文档中的定义

WTF ???

我已根据上述内容修改了一些代码,现在它似乎没有失败。我希望我能告诉你为什么它做了什么以及为什么我做了什么修复它(或者至少再次掩盖它?),但我做不到。也许其他人会遇到这种情况并且可以解决这个问题。

这是我正在做的事情以及我改变了什么:

上面的Textbox使用Validator的附加属性(如ASP.NET验证器,类似于Silverlight Toolkit中的验证器)。当Validator(RequireValidator的基类)附加到控件时,它链接到控件以提供验证作为附加行为。诀窍是它然后尝试验证()当前控件。对于TextBox控件上的RequiredValidator,它为linkedControl上的Text属性调用string.IsNullOrEmpty()。所有这些工作正常,因为这些只是TextBox控件上的属性。但是,在此之后,验证器需要以某种方式告诉控件显示错误指示符和任何错误消息。我这样做是通过提供一个自定义样式,在自己的VisualStateGroup(“ValidationStates”)中包含两个新的VisualStates(“ValidInput”和“InvalidInput”),并且Style的一个元素是支持和接口调用IValidationNotificationControl的Control。

好的,足够的背景。从文档中,我知道在模板应用之后我只能访问TextBox样式的元素(新的visualStates和通知图标)所以我挂钩到了验证器的linkelement的Loaded事件并调用了Validate()这是第一次。好吧,MS的某个人通过从WPF复制粘贴的加载事件描述节省了大约15分钟,这让我花费了大约3-4天的心痛。事实证明,无法保证模板在Silverlight中的Loaded Event中应用。所以,我只是在linkedelement的Loaded事件处理程序中添加了对ApplyTemplate()的调用,故障就消失了。

我的猜测是错误是间歇性的,因为布局(因此模板的应用程序)是异步发生的,有时当我点击加载事件时它就在那里,有时它不是。但我仍然认为它是一个Silverlight Bug,错误表现在哪里,甚至可能指向安全漏洞(如果,但是某些动作,代码中的其他地方,我可以使XAML Parser返回不同于实际的XAMl表示什么......)。哦,好吧......现在似乎在起作用。也许这会帮助别人。

答案 1 :(得分:0)

也许这对某人也有帮助:在另一个帖子中查看我的answer