2013-04-05 91 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>