2013-04-05 78 views
2

我正在尝试在用户控件的窗体中创建3..2..1倒计时。像this。我的想法是在彼此顶部创建两个矩形,一个光线和一个黑色,并且具有径向圆圈作为黑色矩形的剪辑器。径向圆将有角度属性动画,所以它会转过来。WPF剪辑形状

我找到了径向圆的实现,并在我的圆的RenderedGeometry属性上绑定了矩形的Clip属性。下面是结果:

Problem Screenshot

红色的行程是我推子的形状。这似乎是裁剪的一个奇怪的行为,但我有点理解它,但我想知道是否有办法绕过 事实,我的裁剪对象似乎使用RenderedGeometry奇怪的方式。

编辑1:我寻找http://www.youtube.com/watch?v=9FPHTo5V2BQ

+0

这似乎有点过于复杂,什么是你到底是之后的效果? – 2013-04-05 16:03:39

+0

就像这样:http://www.youtube.com/watch?v=9FPHTo5V2BQ。是的,我有时会做复杂的事情,但这是我研究过程的一部分。我还没有找到一个简单的方法来做到这一点。 – 2013-04-05 16:07:40

+0

我不得不在稍后检查它,不幸的是它们限制了我们在办公室的youtube :( – 2013-04-05 16:11:01

回答

2

下面给出的简单衍生形状控制的效果绘制倒计时矩形。你必须设置其Fill(也许Stroke),WidthHeightAngle属性,你可以从0到360

public class CountdownRect : Shape 
{ 
    static CountdownRect() 
    { 
     WidthProperty.OverrideMetadata(typeof(CountdownRect), 
      new FrameworkPropertyMetadata((o, e) => ((CountdownRect)o).UpdateGeometry())); 

     HeightProperty.OverrideMetadata(typeof(CountdownRect), 
      new FrameworkPropertyMetadata((o, e) => ((CountdownRect)o).UpdateGeometry())); 

     StrokeLineJoinProperty.OverrideMetadata(typeof(CountdownRect), 
      new FrameworkPropertyMetadata(PenLineJoin.Round)); 
    } 

    public static readonly DependencyProperty AngleProperty = 
     DependencyProperty.Register("Angle", typeof(double), typeof(CountdownRect), 
      new FrameworkPropertyMetadata((o, e) => ((CountdownRect)o).UpdateGeometry())); 

    public double Angle 
    { 
     get { return (double)GetValue(AngleProperty); } 
     set { SetValue(AngleProperty, value); } 
    } 

    private readonly StreamGeometry geometry = new StreamGeometry(); 

    protected override Geometry DefiningGeometry 
    { 
     get { return geometry; } 
    } 

    private void UpdateGeometry() 
    { 
     if (!double.IsNaN(Width) && !double.IsNaN(Height)) 
     { 
      var angle = ((Angle % 360d) + 360d) % 360d; 
      var margin = StrokeThickness/2d; 
      var p0 = new Point(margin, margin); 
      var p1 = new Point(Width - margin, margin); 
      var p2 = new Point(Width - margin, Height - margin); 
      var p3 = new Point(margin, Height - margin); 

      using (var context = geometry.Open()) 
      { 
       if (angle == 0d) 
       { 
        context.BeginFigure(p0, true, true); 
        context.LineTo(p1, true, false); 
        context.LineTo(p2, true, false); 
        context.LineTo(p3, true, false); 
       } 
       else 
       { 
        var x = p2.X/2d; 
        var y = p2.Y/2d; 
        var a = Math.Atan2(x, y)/Math.PI * 180d; 
        var t = Math.Tan(angle * Math.PI/180d); 

        context.BeginFigure(new Point(x, y), true, true); 

        if (angle < a) 
        { 
         context.LineTo(new Point(x + y * t, p0.Y), true, false); 
         context.LineTo(p1, true, false); 
         context.LineTo(p2, true, false); 
         context.LineTo(p3, true, false); 
         context.LineTo(p0, true, false); 
        } 
        else if (angle < 180d - a) 
        { 
         context.LineTo(new Point(p2.X, y - x/t), true, false); 
         context.LineTo(p2, true, false); 
         context.LineTo(p3, true, false); 
         context.LineTo(p0, true, false); 
        } 
        else if (angle < 180d + a) 
        { 
         context.LineTo(new Point(x - y * t, p2.Y), true, false); 
         context.LineTo(p3, true, false); 
         context.LineTo(p0, true, false); 
        } 
        else if (angle < 360d - a) 
        { 
         context.LineTo(new Point(p0.X, y + x/t), true, false); 
         context.LineTo(p0, true, false); 
        } 
        else 
        { 
         context.LineTo(new Point(x + y * t, p0.Y), true, false); 
        } 

        context.LineTo(new Point(x, p0.Y), true, false); 
       } 
      } 
     } 
    } 
} 
2

您可以通过使用裁剪PathGeometryArcSegment夹您的矩形动画Angle,并为其生成ArcSegment的端点(Point)。

可以使用相同的ArcSegment作为其路径,使用PointAnimationUsingPath动画为端点设置动画。下面是基于一个建议的查尔斯Petzold的出色答卷这里:Drawing pie slices

<UserControl ... > 

    <UserControl.Resources> 
     <Point x:Key="SweepCenter" X="100" Y="100" /> 
     <Size x:Key="SweepRadius" Width="130" Height="130" /> 

     <!-- Start sweeping at twelve o'clock.. --> 
     <Point x:Key="SweepStart" X="100" Y="-30" /> 
     <!-- ..and keep sweeping clockwise until we're (almost) back at the start point: --> 
     <Point x:Key="SweepEnd" X="99.99" Y="-30" /> 

     <Storyboard x:Key="Sweeper" RepeatBehavior="Forever" AutoReverse="False" > 

      <PointAnimationUsingPath Storyboard.TargetName="arc" 
            Storyboard.TargetProperty="Point" 
            Duration="0:0:5"> 
       <PointAnimationUsingPath.PathGeometry> 
        <PathGeometry> 
         <PathFigure StartPoint="{StaticResource SweepStart}"> 
          <ArcSegment Size="{StaticResource SweepRadius}" 
             Point="{StaticResource SweepEnd}" 
             SweepDirection="Clockwise" 
             IsLargeArc="True" /> 
         </PathFigure> 
        </PathGeometry> 
       </PointAnimationUsingPath.PathGeometry> 
      </PointAnimationUsingPath> 

      <BooleanAnimationUsingKeyFrames Storyboard.TargetName="arc" 
              Storyboard.TargetProperty="IsLargeArc" > 
       <DiscreteBooleanKeyFrame KeyTime="0:0:2.5" Value="True" /> 
       <DiscreteBooleanKeyFrame KeyTime="0:0:5" Value="False" /> 
      </BooleanAnimationUsingKeyFrames> 
     </Storyboard> 

    </UserControl.Resources> 

    <Grid Width="200" Height="200" > 
     <Rectangle Fill="Black" /> 
     <Rectangle Fill="Gray" > 
      <Rectangle.Triggers> 
       <EventTrigger RoutedEvent="Loaded"> 
        <BeginStoryboard Storyboard="{StaticResource Sweeper}" /> 
       </EventTrigger> 
      </Rectangle.Triggers> 
      <Rectangle.Clip> 
       <PathGeometry> 
        <PathFigure StartPoint="{StaticResource SweepCenter}" 
           IsClosed="True" > 
         <LineSegment Point="{StaticResource SweepStart}" /> 
         <ArcSegment x:Name="arc" 
            Size="{StaticResource SweepRadius}" 
            Point="{StaticResource SweepStart}" 
            SweepDirection="Clockwise" /> 
        </PathFigure> 
       </PathGeometry> 
      </Rectangle.Clip> 
     </Rectangle> 
    </Grid> 

</UserControl>