Элементы управления WPF: как ссылаться на ресурсы в анимации?

Я написал элемент управления и успешно создал раскадровку, чтобы вызвать анимацию во время инициированных событий. Он изменяет заливку эллипса на определенное время. Вместо того, чтобы писать новый RadialGradientBrush каждый раз, когда мне нужно изменить заливку, я предоставил два из них в ресурсах.

EDIT: у меня есть Ellipse, который является основным компонентом элемента управления и на который влияет анимация. Его реализация проста и выглядит так:

<Ellipse Name="myEllipse" Style="{StaticResource DimStyle}" />

Когда я добавляю его в раскадровку (вместо того, чтобы ссылаться на кисть как на ресурс), моя анимация работает так, как задумано. Когда я ссылаюсь на кисть как на ресурс, я получаю это исключение:

"Cannot find resource named 'IlluminatedStyle'. Resource names are case sensitive."

Внутри раскадровки это то место, где на него в настоящее время ссылаются:

<UserControl.Resources>
    <Storyboard x:Key="Foo">
        <ObjectAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames.KeyFrames>
                <DiscreteObjectKeyFrame KeyTime="0:0:0.01" Value="{StaticResource IlluminatedStyle}" />
                <DiscreteObjectKeyFrame KeyTime="0:0:0.85" Value="{StaticResource DimStyle}" />
            </ObjectAnimationUsingKeyFrames.KeyFrames>
        </ObjectAnimationUsingKeyFrames>
     </Storyboard>
</UserControl.Resources>

Стили почти идентичны, различаются только свойства цвета GradientStop, поэтому для примера я приведу только один стиль.

Стиль, на который ссылается

<UserControl.Resources>
    <Style x:Key="IlluminatedStyle" TargetType="Ellipse">
        <Setter Property="Fill">
            <Setter.Value>
                <RadialGradientBrush>
                    <GradientStop Color="#FF215416" Offset="1"/>
                    <GradientStop Color="#FE38DA2E" Offset="0"/>
                    <GradientStop Color="#FE81FF79" Offset="0.688"/>
                </RadialGradientBrush>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

Итак, как мне правильно сослаться на такой стиль в моем Storyboard?

Примечание. И Storyboard, и Style содержатся в одном и том же теге UserControl.Resources, но в этом примере разделены.

EDIT
Я поставил Style перед Storyboard в UserControl.Resources, и теперь я получаю сообщение об исключении:

  "This Freezable cannot be frozen.
   at System.Windows.Freezable.Freeze()
   at System.Windows.Freezable.GetCurrentValueAsFrozen()
   at System.Windows.Media.Animation.TimelineCollection.GetCurrentValueAsFrozenCore(Freezable source)
   at System.Windows.Freezable.CloneCoreCommon(Freezable sourceFreezable, Boolean useCurrentValue, Boolean cloneFrozenValues)
   at System.Windows.Media.Animation.Timeline.GetCurrentValueAsFrozenCore(Freezable sourceFreezable)
   at System.Windows.Freezable.GetCurrentValueAsFrozen()
   at System.Windows.Media.Animation.Clock..ctor(Timeline timeline)
   at System.Windows.Media.Animation.TimelineGroup.AllocateClock()
   at System.Windows.Media.Animation.Clock.AllocateClock(Timeline timeline, Boolean hasControllableRoot)"

person Jeff LaFay    schedule 02.12.2010    source источник
comment
Они оба находятся в одном и том же UserControl.Resources, но в каком порядке? Ресурсы, на которые ссылаются (с помощью StaticResource), должны располагаться перед ссылающимся на них.   -  person Wonko the Sane    schedule 02.12.2010
comment
Стиль после него в ресурсах. Что имеет значение в WPF? Я немного удивлен, потому что я могу написать класс за другим в файле CS, но при этом ссылаться на нижний класс в верхнем классе и правильно компилировать.   -  person Jeff LaFay    schedule 02.12.2010
comment
Порядок имеет значение для StaticResources, а не для DynamicResources.   -  person Wonko the Sane    schedule 02.12.2010
comment
@Jon, я добавил трассировку стека, а также значения свойства KeyTime в DiscreteObjectKeyFrames. @Wonko, идеально ли сделать мои ресурсы динамическими в этом сценарии?   -  person Jeff LaFay    schedule 02.12.2010
comment
Запустите приложение внутри отладчика и, когда возникнет исключение, посмотрите, какой именно Freezable является параметром GetCurrentValueAsFrozenCore (3-й в стеке вызовов). У тебя здесь отладчик, используй его. :-)   -  person Jon    schedule 02.12.2010
comment
@jlafay: есть компромисс между динамическими и статическими ресурсами. Как правило, динамические ресурсы используются для вещей, которые будут меняться (т. е. это один из способов реализации привязки меток для приложений, допускающих изменение языка). Здесь вы всегда используете один и тот же ресурс, поэтому Static, вероятно, лучше. Вам лучше выяснить проблему с Freezable, с которой @Jon начал вас.   -  person Wonko the Sane    schedule 02.12.2010
comment
Когда возникает исключение, источником $exception.Source является WindowsBase, но я уверен, что это вам не поможет. Я попробовал точку останова, в которой вызывающий метод вызывает Begin() на раскадровке в надежде, что я смогу перейти к вызову, но он выдает, когда вызывается Begin().   -  person Jeff LaFay    schedule 02.12.2010
comment
Вам нужно взломать отладчик, поскольку исключение выдается для проверки стека вызовов. Для этого посмотрите, какой тип исключения, и используйте эту технику для автоматического прерывания работы отладчика: blackwasp .co.uk/VSBreakOnException.aspx   -  person Jon    schedule 02.12.2010
comment
В отладчике уже ломается, никакой дополнительной информации я не получаю. В моем случае FAQ бесполезен, потому что я до сих пор не знаю, как найти то, что вы просите. Как я уже сказал, он прерывается, когда вызывается метод отделенного кода элемента управления, и этот метод вызывает Begin() в раскадровке. Где я могу найти данные, которые вы запрашиваете?   -  person Jeff LaFay    schedule 02.12.2010
comment
Поскольку я ничего не получаю, я также добавил строку кода, которая является основным компонентом элемента управления. Я не могу выполнить анимацию XAML, поскольку она не позволяет мне добавлять точки останова. Честно говоря, что вы ищете?   -  person Jeff LaFay    schedule 02.12.2010


Ответы (2)


Есть три причины, по которым Freezable нельзя заморозить:

  • Он имеет анимированные или связанные с данными свойства.
  • У него есть свойства, которые задаются динамическим ресурсом.
  • Он содержит подобъекты Freezable, которые нельзя заморозить.

Итак, сначала выясните, какой Freezable вызывает проблемы, а затем проверьте вышеперечисленное.

person Jon    schedule 02.12.2010
comment
Спасибо за информацию, я новичок в WPF и ценю руководство. - person Jeff LaFay; 02.12.2010
comment
Учитывая, что это анимация раскадровки, которая выдает это исключение, я полагаю, что это имеет смысл, но не имеет смысла, учитывая, что она будет работать, когда я не ссылаюсь на значения KeyFrame как на стили. Может быть, мне стоит отказаться от повторного использования кода и оставить этот в покое. Я не знаю, где решить проблему. - person Jeff LaFay; 02.12.2010
comment
Я придумал решение, но не смог отладить то, как вы просили. В любом случае спасибо. - person Jeff LaFay; 02.12.2010

Видя, что я новичок в WPF и XAML, я сделал ошибку, сделав свои ресурсы стилем, и не понял, что мог бы просто сделать кисти ресурсом и вообще избежать стилей.

Я сохранил ссылку на значения DiscreteObjectKeyFrames как статическую для новых ресурсов кисти. Я изменил Эллипс на это:

<Ellipse Name="myEllipse" Fill="{StaticResource DimBrush" />

Свойство стиля было удалено, и я напрямую назначил кисть свойству заливки. В теге ObjectAnimationUsingKeyFrames я добавил Fill вместо Storyboard.TargetProperty, так как больше не использовал стиль для украшения заливки. Теперь DiscreteObjectKeyFrame выглядят так:

<DiscreteObjectKeyFrame KeyTime="0:0:0.01" Value="{StaticResource IlluminatedBrush}" />
<DiscreteObjectKeyFrame KeyTime="0:0:0.85" Value="{StaticResource DimBrush}" />

Мои ресурсы намного проще, не обернуты в стиль и ИМО, более элегантны. Также кисти определяются перед анимацией в моем окончательном решении.

<UserControl.Resources>
    <RadialGradientBrush x:Key="DimBrush" >
        <GradientStop Color="#FF21471A" Offset="1"/>
        <GradientStop Color="#FF33802F" Offset="0"/>
        <GradientStop Color="#FF35932F" Offset="0.688"/>
    </RadialGradientBrush>
    <RadialGradientBrush x:Key="IlluminatedBrush">
        <GradientStop Color="#FF215416" Offset="1"/>
        <GradientStop Color="#FE38DA2E" Offset="0"/>
        <GradientStop Color="#FE81FF79" Offset="0.688"/>
    </RadialGradientBrush>
    <!-- Storyboard code follows... -->
</UserControl.Resources>

Теперь все работает как задумано. Лучшее предположение, которое я могу сделать, это то, что стили нельзя заморозить, поскольку они были компонентами, которые я удалил, и я больше не получаю исключений в отношении замораживаемых, которые нельзя заморозить.

person Jeff LaFay    schedule 02.12.2010