代码之家  ›  专栏  ›  技术社区  ›  Mark Heath

绑定到故事板上的附加行为

  •  3
  • Mark Heath  · 技术社区  · 15 年前

    我已经为情节提要创建了一个附加的依赖项属性,目的是使我能够在情节提要完成事件激发时调用ViewModel上的方法:

    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中使用它,并使用绑定语法:

    <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=“无法将属性”style“中的值转换为”system.windows.style“类型的对象。”无法冻结此情节提要时间线树以供跨线程使用。标记文件“testwpfapp;component/window1.xaml”中的对象“labelhello”出错

    是否有任何方法可以让绑定语法使用故事板的附加ICommand属性?

    3 回复  |  直到 15 年前
        1
  •  1
  •   Ray Booysen    15 年前

    这是设计出来的。如果将可冻结的对象放入样式中,样式将被冻结以允许跨线程访问。但是绑定本质上是一个表达式,这意味着它不能被冻结,因为数据绑定是单线程的。

    如果需要这样做,请将触发器放在样式外部的框架元素下,而不是样式中。您可以在网格中执行此操作。触发器部分。这确实有点糟糕,因为您的样式不再完整,您必须复制触发器,但它是WPF中的“按设计”特性。

    在msdn社交论坛上的完整答案是 here .

        2
  •  0
  •   Dan Vanderboom    15 年前

    您可以创建一个新的Freezable派生类来作为填充程序启动故事板。将该填充程序对象上的属性绑定到情节提要名称。这样,您就不必复制触发器或将它们存储在样式之外。

        3
  •  0
  •   Mark Heath    15 年前

    为了解决这个问题,我创建了一组附加属性,称为故事板帮助器( source code here )我放弃了尝试将它们附加到故事板本身,现在附加到任何(任意)框架元素,以便在故事板完成时在我的ViewModel上调用ICommand,以及绑定到我的ViewModel上的特定事件以启动故事板。第三个附加属性指定了我们要处理的情节提要:

    <FrameworkElement
       my:StoryboardHelpers.Storyboard="{StaticResource rightAnswerAnimation}"
       my:StoryboardHelpers.Completed="{Binding CompletedCommand}"
       my:StoryboardHelpers.BeginEvent="{Binding StartCorrectAnswer}" />