2

这是设置:

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

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转换为 type hookitupright.com.silverlight.controls.general.Dialog。” 发生在上述 XAML InitializeComponent()的父级中。UserControl

具体来说,它发生在这里:

this.AddUpdateDialog = ((hookitupright.com.silverlight.controls.general.Dialog)(this.FindName("AddUpdateDialog")));

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

我试过了:

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

    2a。认为这可能与 TextBox 的 TwoWay 绑定有关,我删除了绑定。还是失败。

更新:因此,鉴于上面的 (2),我离开了已注释掉的文本框,决定继续做其他事情,然后回到这里,希望有些事情会向我展示。不幸的是,它似乎也因文本框而失败,只是频率较低。

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

问题是它不会每次都失败。它大约有 20% 的时间会爆炸。当它工作时,即使这个对话框也能正常工作?

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

4

2 回答 2

1

经过大量研究和挫折,我相信它与此有关:http: //blogs.msdn.com/silverlight_sdk/archive/2008/10/24/loaded-event-timing-in-silverlight.aspx

Silverlight 中的 Loaded 事件与 (a) WPF 中的定义不匹配,因此 (b) 他们从 WPF 粘贴到 Silverlight 文档中的定义

怎么回事???

我已经根据上述修改了一些代码,现在它似乎没有失败。我希望我能准确地告诉你为什么它做了什么以及为什么我做了什么修复它(或者至少再次掩盖它??),但我不能。也许其他人会遇到这个并且可以弄清楚。

这是我在做什么以及我改变了什么:

上面的文本框使用了验证器的附加属性(如 ASP.NET 验证器,类似于 Silverlight 工具包中的验证器)。当 Validator(RequireValidator 的基类)附加到控件时,它链接到该控件以提供作为附加行为的验证。诀窍是它然后尝试 Validate() 当前控件。对于TextBox 控件上的RequiredValidator,它为linkedControl 上的Text 属性调用string.IsNullOrEmpty()。所有这些都可以正常工作,因为这些只是 TextBox 控件上的属性。然而,在那之后,验证器需要以某种方式告诉控件显示错误指示器和任何错误消息。我通过提供一个包含两个新 VisualStates(“ValidInput”和“InvalidInput”

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

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

于 2009-01-27T00:32:43.033 回答
0

也许这对某人也有帮助:看看我在另一个线程中的答案:

于 2009-06-30T11:42:08.833 回答