4

我正在尝试在 WPF 中创建动画,但我对放置所有内容的位置感到很困惑。我需要一个不断增长的圆圈,就像画自己一样。

为此,我有一个设计精美的圆圈(一个描边的圆圈,下面有一个模糊的描边圆圈)然后我有另一个带有 StrokeDashArray 的圆圈。我计划将这个圆圈用作第一个圆圈的 opacityMask,并为 StrokeDashArray 设置动画以显示圆圈。

我一直在玩,我可以将 StrokeDashArray 从 [0, 100] 修改为 [50 100] 并且我得到一条覆盖圆圈的增长线(我真的不明白 0 100 和 50 100 来自哪里......只是尝试直到它看起来不错。

所以现在我的问题是在哪里分发这些东西。

到目前为止,我的代码如下所示:

<UserControl bla bla bla bla>
    <!-- The mask that should be animated -- >
    <Ellipse Name="Mask" Stroke="White"StrokeThickness="13" StrokeDashArray="10 100"/>
    <!-- StrokeDashArray should be animated from "0 100" to "50 100"  -->

    <!-- The Blurry shadow of the line -->
    <Ellipse Name="blurry" Stroke="#FF7CA2CE" StrokeThickness="5">
        <Ellipse.Effect>
            <BlurEffect/>
        </Ellipse.Effect>
        <Ellipse.OpacityMask>
            <VisualBrush Visual="{Binding ElementName=Mask}"/>
        </Ellipse.OpacityMask>
    </Ellipse>

    <!-- The line itself -->
    <Ellipse Name="core" Stroke="Blue" StrokeThickness="1">
        <Ellipse.OpacityMask>
            <VisualBrush Visual="{Binding ElementName=Mask}"/>
        </Ellipse.OpacityMask>
    </Ellipse>
</UserControl>

所以现在我需要在 StrokeDashArray 中的第一个元素上执行动画并从后面的代码(C#)启动它我还可以让动画作为资源在某个地方并从代码启动它,或者在代码中执行整个动画,我不在乎,但请具体说明在哪里添加代码。我感到迷茫。

我还尝试将模糊线和核心线添加到一个网格,然后将 VisualBrush 应用到它(所以我只应用一次,而不是两次)但效果更难看,因为模糊线被剪切并且不像我们那样柔和地结束想要它是hehehe

Sooo,任何帮助?!?!?!?!?!

4

3 回答 3

10

实际上,您可以为 StrokeDashOffset 设置动画,而不是尝试为 StrokeDashArray 设置动画。

<Rectangle
   Width="70"
   Height="70"
   StrokeDashArray="2 0 0 2"
   StrokeThickness="2"
   Stroke="Black"
   Opacity="1"
   Fill="Transparent">
   <Rectangle.Triggers> 
            <EventTrigger RoutedEvent="FrameworkElement.Loaded"> 
                <BeginStoryboard> 
                    <Storyboard> 
                        <DoubleAnimation 
                           To="20" 
                           Duration="0:0:5" 
                           RepeatBehavior="Forever" 
                           By="2" 
                           Storyboard.TargetProperty="StrokeDashOffset" /> 
                    </Storyboard> 
                </BeginStoryboard> 
            </EventTrigger> 
        </Rectangle.Triggers> 
   </Rectangle>
于 2017-08-11T14:57:45.827 回答
6

这有点棘手,因为你不能真正为StrokeDashArray里面DoubleCollection的值设置动画并让它反映在 UI 中。

一种选择是为double属性设置动画并创建一个DoubleCollection绑定到StrokeDashArray.

这是一个工作示例:

xml:

<Window x:Class="WpfApplication21.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="211.75" Width="213" Name="UI">

    <Grid DataContext="{Binding ElementName=UI}">

        <Ellipse x:Name="lo" Stroke="White" StrokeThickness="13" StrokeDashArray="{Binding StrokeArray}" />

        <Ellipse Name="blurry" Stroke="#FF7CA2CE" StrokeThickness="5">
            <Ellipse.Effect>
                <BlurEffect/>
            </Ellipse.Effect>
            <Ellipse.OpacityMask>
                <VisualBrush Visual="{Binding ElementName=lo}"/>
            </Ellipse.OpacityMask>
        </Ellipse>

        <!-- The line itself -->
        <Ellipse Name="core" Stroke="Blue" StrokeThickness="1">
            <Ellipse.OpacityMask>
                <VisualBrush Visual="{Binding ElementName=lo}"/>
            </Ellipse.OpacityMask>
        </Ellipse>

        <Button Content="Start" HorizontalAlignment="Left" Height="49" Margin="29,65,0,0" VerticalAlignment="Top" Width="150" Click="Button_Click_1"/>

    </Grid>
</Window>

代码:

namespace WpfApplication21
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        public double StrokeValue
        {
            get { return (double)GetValue(StrokeValueProperty); }
            set { SetValue(StrokeValueProperty, value); }
        }

        public static readonly DependencyProperty StrokeValueProperty =
            DependencyProperty.Register("StrokeValue", typeof(double), typeof(MainWindow)
            , new PropertyMetadata(0.0, new PropertyChangedCallback(OnStrokeValueChanged)));

        private static void OnStrokeValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as MainWindow).StrokeArray = new DoubleCollection { (double)e.NewValue, 100 };
        }


        public DoubleCollection StrokeArray
        {
            get { return (DoubleCollection)GetValue(StrokeArrayProperty); }
            set { SetValue(StrokeArrayProperty, value); }
        }

        public static readonly DependencyProperty StrokeArrayProperty =
            DependencyProperty.Register("StrokeArray", typeof(DoubleCollection), typeof(MainWindow)
            , new PropertyMetadata(new DoubleCollection { 0, 100 }));


    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        var storyboard = new Storyboard();
        var animation = new DoubleAnimation(0,50,new Duration(TimeSpan.FromSeconds(5)));
        storyboard.Children.Add(animation);
        Storyboard.SetTarget(animation, this);
        Storyboard.SetTargetProperty(animation,new PropertyPath( MainWindow.StrokeValueProperty));
        storyboard.Begin();
    }

    }
}
于 2013-04-10T11:25:18.580 回答
0

动画在 Expression Blend 中更容易设计和调整。

根据您拥有的 Visual Studio 版本,它可能附带也可能不附带,或者可能必须单独获取。

Visual Studio 2012 附带了 Expression Blend(但您需要获得 Visual Studio 2012 Update 2 以获得 WPF 支持),否则您可以单独获得 Expression Blend 4,或者作为 Expression Studio 的一部分。

然后根据您的动画要求:

  • 您可以设计一个故事板,然后您可以从后面的代码或附加的行为动作(ControlStoryboardAction)开始

  • 或者您可以使用 VisualStateManager 并在状态面板中的 Blend 中,在状态组中定义一组状态,然后告诉 VisualStateManager 您要设置哪个“状态”......您将获得状态之间的动画(如果您设置了正确的值)....使用 VisualStateManager.GoToState() 或附加的行为 GotoToStateAction 来更改状态。

设计好动画后,如果您希望将其转换为代码隐藏(手动)来构建和操作该动画,则可以,但通常您不会这样做,除非特殊情况。

(有一个工具可以在某种程度上为您进行转换,但似乎不可用...... http://www.xamlt.com/


一些帮助您入门的链接:

于 2013-04-10T10:58:12.627 回答