为什么ScrollBar的ValueChanged EventTrigger将动画绑定到以前的值

时间:2014-07-03 09:10:50

标签: wpf xaml storyboard scrollbar eventtrigger

我的WPF应用程序中有一个奇怪的行为。

我正在尝试在ScrollBar.ValueChanged事件上启动厚度动画以设置元素边距的动画,但每次滚动条值更改时,动画都会绑定到滚动条的OLD值。

导致滚动条值与边距元素之间出现间隙。

<UserControl.Resources>

        <Storyboard x:Key="AnimationScrollTest">
            <ThicknessAnimation Storyboard.TargetName="ElementTest" Storyboard.TargetProperty="Margin" Duration="0:0:0:0.3" 
                                To="{Binding ElementName=ScrollBarTest, Path=Value, Converter={StaticResource MyVerticalScrollBarValueToMarginConverter}}" />
        </Storyboard>
<UserControl.Resources>

<Grid>
   <ScrollBar x:Name="ScrollBarTest" Grid.RowSpan="3" Grid.ColumnSpan="2" Orientation="Vertical" Right" VerticalAlignment="Stretch" SmallChange="10" LargeChange="100" Value="0" Maximum="2000" >
            <ScrollBar.Triggers>
                <EventTrigger RoutedEvent="ScrollBar.ValueChanged" >
                    <BeginStoryboard Storyboard="{StaticResource AnimationScrollTest}" />
                </EventTrigger>
            </ScrollBar.Triggers>
        </ScrollBar>

        <Border x:Name="ElementTest" Grid.RowSpan="3" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Top" Width="50" Height="50" Background="Red"></Border>
</Grid>




public class VerticalScrollBarValueToMarginConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return new Thickness(0, (Double)value, 0, 0);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
  • 当EventTrigger链接到ScrollBar.Scroll事件时,它运行良好。
  • 在转换器中添加断点时,Convert方法中的value对象具有正确的值
  • 如果ElementTest边距直接绑定到ScrollBar值(没有动画),它也可以正常工作。

任何想法??

非常感谢

PS:抱歉英语不好,我是法国人!

1 个答案:

答案 0 :(得分:0)

我尝试使用附加属性解决之前的值问题

XAML

<Grid xmlns:l="clr-namespace:CSharpWPF">
    <ScrollBar x:Name="ScrollBarTest"
               Grid.RowSpan="3"
               Grid.ColumnSpan="2"
               Orientation="Vertical"
               HorizontalAlignment="Right"
               VerticalAlignment="Stretch"
               SmallChange="10"
               LargeChange="100"
               Value="0"
               Maximum="2000">
    </ScrollBar>
    <Border x:Name="ElementTest"
            Grid.RowSpan="3"
            Grid.ColumnSpan="2"
            HorizontalAlignment="Center"
            VerticalAlignment="Top"
            Width="50"
            Height="50"
            Background="Red"
            l:ScrollBarToMarginAnimator.ScrollBar="{Binding ElementName=ScrollBarTest}"></Border>
</Grid>

我已从此处删除了故事板,并将附加属性l:ScrollBarToMarginAnimator.ScrollBar添加到目标元素并绑定到滚动条ScrollBarTest

附加属性的类

namespace CSharpWPF
{
    public class ScrollBarToMarginAnimator : DependencyObject
    {

        public static ScrollBar GetScrollBar(DependencyObject obj)
        {
            return (ScrollBar)obj.GetValue(ScrollBarProperty);
        }

        public static void SetScrollBar(DependencyObject obj, ScrollBar value)
        {
            obj.SetValue(ScrollBarProperty, value);
        }

        // Using a DependencyProperty as the backing store for ScrollBar.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScrollBarProperty =
            DependencyProperty.RegisterAttached("ScrollBar", typeof(ScrollBar), typeof(ScrollBarToMarginAnimator), new PropertyMetadata(null, OnScrollBarChanged));

        private static void OnScrollBarChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

            ScrollBar sb = e.NewValue as ScrollBar;
            if (sb != null)
                sb.Scroll += (ss, ee) =>
                    {
                        ThicknessAnimation ta = new ThicknessAnimation(new Thickness(0, sb.Value, 0, 0), TimeSpan.FromMilliseconds(300));
                        (d as FrameworkElement).BeginAnimation(FrameworkElement.MarginProperty, ta);
                    };
        }

    }
}

在这个课程中,我正在收听绑定滚动条的Scroll事件,并在附加元素的ThicknessAnimation属性上启动Margin

上面的解决方案将监听滚动条中的任何更改,并通过设置边框边缘的动画来做出相应的反应。

多个滚动条

XAML

<Grid xmlns:l="clr-namespace:CSharpWPF">
    <ScrollBar x:Name="vertical"
           Grid.RowSpan="3"
           Grid.ColumnSpan="2"
           Orientation="Vertical"
           HorizontalAlignment="Right"
           VerticalAlignment="Stretch"
           SmallChange="10"
           LargeChange="100"
           Value="0"
           Maximum="2000"/>
    <ScrollBar x:Name="horizontal"
           Grid.RowSpan="3"
           Grid.ColumnSpan="2"
           Orientation="Horizontal"
           HorizontalAlignment="Stretch"
           VerticalAlignment="Top"
           SmallChange="10"
           LargeChange="100"
           Value="0"
           Maximum="2000"/>
    <Border x:Name="ElementTest"
        Grid.RowSpan="3"
        Grid.ColumnSpan="2"
        HorizontalAlignment="Center"
        VerticalAlignment="Top"
        Width="50"
        Height="50"
        Background="Red"
        l:ScrollBarToMarginAnimator.Vertical="{Binding ElementName=vertical}"
        l:ScrollBarToMarginAnimator.Horizontal="{Binding ElementName=horizontal}"/>
</Grid>

我添加了另一个滚动条并将两个属性附加到边框。

CS

namespace CSharpWPF
{

    public class ScrollBarToMarginAnimator : DependencyObject
    {

        public static ScrollBar GetVertical(DependencyObject obj)
        {
            return (ScrollBar)obj.GetValue(VerticalProperty);
        }

        public static void SetVertical(DependencyObject obj, ScrollBar value)
        {
            obj.SetValue(VerticalProperty, value);
        }

        // Using a DependencyProperty as the backing store for Vertical.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VerticalProperty =
            DependencyProperty.RegisterAttached("Vertical", typeof(ScrollBar), typeof(ScrollBarToMarginAnimator),
            new PropertyMetadata(null, (d, e) => AttachAnimation(d, e, true)));

        public static ScrollBar GetHorizontal(DependencyObject obj)
        {
            return (ScrollBar)obj.GetValue(HorizontalProperty);
        }

        public static void SetHorizontal(DependencyObject obj, ScrollBar value)
        {
            obj.SetValue(HorizontalProperty, value);
        }

        // Using a DependencyProperty as the backing store for Horizontal.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HorizontalProperty =
            DependencyProperty.RegisterAttached("Horizontal", typeof(ScrollBar), typeof(ScrollBarToMarginAnimator),
            new PropertyMetadata(null, (d, e) => AttachAnimation(d, e, false)));


        private static void AttachAnimation(DependencyObject d, DependencyPropertyChangedEventArgs e, bool isVertical)
        {
            ScrollBar sb = e.NewValue as ScrollBar;
            if (sb != null)
                sb.Scroll += (ss, ee) =>
                {
                    FrameworkElement fw = d as FrameworkElement;
                    Thickness newMargin = fw.Margin;
                    if (isVertical)
                        newMargin.Top = sb.Value;
                    else
                        newMargin.Left = sb.Value;

                    ThicknessAnimation ta = new ThicknessAnimation(newMargin, TimeSpan.FromMilliseconds(300));
                    fw.BeginAnimation(FrameworkElement.MarginProperty, ta);
                };
        }

    }
}

我创建了两个属性,并使用标志

附加动画
相关问题