Прерывистое InavlidCastException в UserControl.InitializeComponent () - PullRequest
2 голосов
/ 23 января 2009

Вот настройки:

У меня есть библиотека элементов управления 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>

Я использую этот диалог во многих местах без проблем. Тем не менее, в одном приложении, вложенном примерно в 3-4 пользовательских элемента управления из RootVisual, я использую его следующим образом:

<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." это происходит в InitializeComponent() для родителя UserControl вышеупомянутого XAML.

Если быть точным, это происходит прямо здесь:

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

Когда я ставлю точку останова, большую часть времени FindName возвращает типизированный объект Dialog, но иногда он возвращает ContentControl (основа для Dialog), и это не удается. XAML не изменился. Это статично ... Поскольку исключение является прерывистым и возникает в сгенерированном коде, я в растерянности.

Я пробовал:

  1. Переместил весь контент для диалога в отдельный UserControl - казалось, только усугубил проблему
  2. Закомментируйте части и посмотрите, когда это работает ... хорошо, если я полностью закомментирую TextBox, он больше не будет работать. Все остальное (включая прикрепленное свойство пользовательской проверки), похоже, никак не влияет.

    2a. Думая, что это может быть связано с привязкой TwoWay к TextBox, я удалил привязку. По-прежнему не удается.

ОБНОВЛЕНИЕ: Поэтому, учитывая (2) выше, я оставил текстовое поле закомментированным, решил перейти к другим вещам и вернуться к этому с надеждой, что что-то откроется мне. К сожалению, он также не работает с Textbox, только реже.

Кроме того, у меня есть этот элемент управления в точно такой же конфигурации в другом пользовательском контроле в том же приложении (и на том же уровне в VisualTree), и он не выходит из строя вообще. Поэтому я буквально скопировал и вставил неисправный XAML в Main.xaml (мой корневой визуал) и, конечно же, он тоже не потерпит неудачу. Предполагая, что XAML загружен в последовательности (сверху вниз), неисправный элемент управления, вероятно, является одним из последних загруженных. Моя единственная гипотеза сейчас заключается в том, что есть некоторая временная вещь, которая происходит, когда Iam все еще загружает визуальное дерево, я начинаю получать * Завершенные события при загрузке данных через службу WCF, и что они вызывают макет до того, как визуальное дерево будет полностью загружен, что вызывает некоторые побочные эффекты ... Я проверю это.

Проблема в том, что он НЕ терпит неудачу каждый раз. Это взрывается примерно в 20% случаев. Когда это работает, все работает, даже этот диалог?

Эта проблема связана, если не с той же проблемой: когда я «исправляю» инвалидность, закомментировав необходимую функциональность, я гораздо реже, но периодически получаю этот недействительный атрибут (когда атрибут / свойство на самом деле есть).

Ответы [ 2 ]

1 голос
/ 27 января 2009

После долгих, долгих исследований и разочарований, я полагаю, это связано с этим: http://blogs.msdn.com/silverlight_sdk/archive/2008/10/24/loaded-event-timing-in-silverlight.aspx

Событие Loaded в Silverlight не соответствует определению (а) того, чем оно является в WPF и, следовательно, (b) определению, которое они вставили в документацию Silverlight из WPF

ВТФ ???

Я изменил некоторый код на основе вышеизложенного, и теперь он, похоже, не дает сбоя. Хотел бы я сказать вам точно, почему он сделал то, что сделал и почему то, что я сделал, исправило это (или, по крайней мере, замаскировало это снова ??), но я не могу. Может быть, кто-то еще столкнется с этим и сможет понять это.

Вот что я делал и что изменил:

В приведенном выше текстовом поле используется свойство Attached для валидатора (например, валидаторы ASP.NET и аналогичные тем, которые есть в Silverlight Toolkit). Когда Validator (базовый класс для RequireValidator) присоединен к элементу управления, он связывается с элементом управления для обеспечения проверки в качестве присоединенного поведения. Хитрость в том, что он затем пытается проверить () текущий элемент управления. Для RequiredValidator в элементе управления TextBox он вызывает string.IsNullOrEmpty () для свойства Text в connectedControl. Все это прекрасно работает, так как это просто свойства элемента управления TextBox. Однако сразу после этого валидатору необходимо каким-то образом указать элементу управления на отображение индикатора ошибки и любого сообщения об ошибке. Я делаю это путем предоставления пользовательского стиля, который включает в себя два новых VisualStates («ValidInput» и «InvalidInput») в их собственной VisualStateGroup («ValidationStates»), и что один из элементов стиля является элементом управления, который поддерживает и интерфейс называется IValidationNotificationControl.

Хорошо, достаточно фона. Из документации я знал, что могу получить доступ только к элементам стиля TextBox (новые visualStates и значок уведомления) ПОСЛЕ применения шаблона, поэтому я подключился к событию Loaded для связующего элемента для валидатора и вызвал Validate () там впервые. Ну, кто-то в MS сэкономил около 15 минут, скопировав описание загруженного события из WPF, и это стоило мне 3-4 дней душевной боли. Оказывается, нет никакой гарантии, что шаблон будет применен в Loaded Event в Silverlight. Поэтому я просто добавил вызов ApplyTemplate () в обработчик событий Loaded для linkedelement, и ошибка исчезла.

Я предполагаю, что ошибка была прерывистой, потому что Layout (и, следовательно, применение шаблона) происходит асинхронно, и иногда это происходило, когда я нажимал на событие Loaded, а иногда - нет. Но я все еще думаю, что это ошибка Silverlight относительно того, где ошибка проявилась, и может даже указывать на дыру в безопасности (если, но какое-то действие, где-то еще в коде, я могу заставить парсер XAML возвращать тип, отличный от на что указывает фактический XAMl ...). Ну да ладно ... похоже, сейчас работает. Может быть, это поможет кому-то еще.

0 голосов
/ 30 июня 2009

Может быть, это кому-то тоже поможет: взгляните на мой ответ в другой теме:

...