Привязать к прикрепленному поведению на раскадровке

Я создал прикрепленное свойство зависимостей для раскадровок, чтобы позволить мне вызывать метод в моей ViewModel, когда срабатывает событие Storyboard Completed:

public static class StoryboardExtensions
{
    public static ICommand GetCompletedCommand(DependencyObject target)
    {
        return (ICommand)target.GetValue(CompletedCommandProperty);
    }

    public static void SetCompletedCommand(DependencyObject target, ICommand value)
    {
        target.SetValue(CompletedCommandProperty, value);
    }

    public static readonly DependencyProperty CompletedCommandProperty =
        DependencyProperty.RegisterAttached(
            "CompletedCommand",
            typeof(ICommand),
            typeof(StoryboardExtensions),
            new FrameworkPropertyMetadata(null, OnCompletedCommandChanged));

    static void OnCompletedCommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        Storyboard storyboard = target as Storyboard;
        if (storyboard == null) throw new InvalidOperationException("This behavior can be attached to Storyboard item only.");
        storyboard.Completed += new EventHandler(OnStoryboardCompleted);
    }

    static void OnStoryboardCompleted(object sender, EventArgs e)
    {                        
        Storyboard item = ... // snip
        ICommand command = GetCompletedCommand(item);
        command.Execute(null);
    }
}

затем я пытаюсь использовать его в XAML с синтаксисом Binding:

<Grid>
    <Grid.Resources>
        <Storyboard x:Key="myStoryboard" my:StoryboardExtensions.CompletedCommand="{Binding AnimationCompleted}">
            <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:5" />
        </Storyboard>

        <Style x:Key="myStyle" TargetType="{x:Type Label}">
            <Style.Triggers>
                <DataTrigger 
                 Binding="{Binding Path=QuestionState}" Value="Correct">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard Storyboard="{StaticResource myStoryboard}" />
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>

    </Grid.Resources>
    <Label x:Name="labelHello" Grid.Row="0" Style="{StaticResource myStyle}">Hello</Label>
</Grid>

Это не удается со следующим исключением:

Произошло исключение System.Windows.Markup.XamlParseException Message="Невозможно преобразовать значение атрибута "Стиль" в объект типа "System.Windows.Style". Невозможно заморозить это дерево временной шкалы раскадровки для использования в потоках. Ошибка в объекте "labelHello" в файл разметки 'TestWpfApp;component/window1.xaml'

Есть ли способ заставить синтаксис Binding работать с присоединенным свойством ICommand для раскадровки?


person Mark Heath    schedule 18.09.2009    source источник


Ответы (3)


Это что-то по дизайну. Если у вас есть замораживаемый объект, помещенный в стиль, стиль будет заморожен, чтобы обеспечить межпоточный доступ. Но ваша привязка, по сути, является выражением, что означает, что ее нельзя заморозить, поскольку привязка данных является однопоточной.

Если вам нужно это сделать, поместите триггер вне стиля под элементом фреймворка, а не в стиле. Вы можете сделать это в разделе Grid.Triggers. Это немного отстой, так как ваш стиль больше не завершен, и вам нужно дублировать триггеры, но это функция «по дизайну» в WPF.

Полный ответ на социальных форумах MSDN: здесь.

person Ray Booysen    schedule 18.09.2009
comment
но Grid.Triggers не будет принимать DataTrigger, только EventTrigger - person Mark Heath; 18.09.2009
comment
Хм, это усложняет задачу. Тогда не совсем уверен. - person Ray Booysen; 18.09.2009
comment
Идея относительно замораживаемых объектов все еще актуальна, но есть ли решение? Точно сказать не могу. - person Ray Booysen; 18.09.2009

Вы можете создать новый класс, производный от Freezable, для запуска раскадровки в качестве прокладки. Привяжите свойство этого объекта-оболочки к имени раскадровки. Таким образом, вам не придется дублировать триггеры или хранить их вне стиля.

person Dan Vanderboom    schedule 18.09.2009

Чтобы обойти эту проблему, я создал набор вложенных свойств, называемых помощниками раскадровки (исходный код здесь). Я отказался от попыток прикрепить их к самой раскадровке и теперь присоединяюсь к любому (произвольному) элементу фреймворка для вызова ICommand в моей ViewModel, когда раскадровка завершена, а также к привязке к определенному событию в моей ViewModel для запуска раскадровки. . Третье прикрепленное свойство определяет раскадровку, с которой мы имеем дело:

<FrameworkElement
   my:StoryboardHelpers.Storyboard="{StaticResource rightAnswerAnimation}"
   my:StoryboardHelpers.Completed="{Binding CompletedCommand}"
   my:StoryboardHelpers.BeginEvent="{Binding StartCorrectAnswer}" />
person Mark Heath    schedule 06.10.2009
comment
Попробуйте эту ссылку: learninggames.codeplex.com/SourceControl/ набор изменений/просмотр/ - person Curt Nichols; 11.03.2011