WPF裁剪具有形状 [英] WPF Clipping with a shape

查看:52
本文介绍了WPF裁剪具有形状的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试以用户控件的形式创建3..2..1倒计时.类似于

解决方案

下面显示的简单的派生Shape控件绘制了倒数矩形.您必须设置其 Fill (也许是 Stroke ), Width Height Angle 属性,您可以将 Angle 的动画从0设置为360.

 公共类CountdownRect:形状{静态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),新的FrameworkPropertyMetadata(PenLineJoin.Round));}公共静态只读DependencyProperty AngleProperty =DependencyProperty.Register("Angle",typeof(double),typeof(CountdownRect),new FrameworkPropertyMetadata((o,e)=>(((CountdownRect)o).UpdateGeometry()));公共双角{get {return(double)GetValue(AngleProperty);}设置{SetValue(AngleProperty,value);}}私有只读StreamGeometry几何=新的StreamGeometry();受保护的重写Geometry DefiningGeometry{得到{返回几何;}}私有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);使用(var context = geometry.Open()){如果(角度== 0d){context.BeginFigure(p0,true,true);context.LineTo(p1,true,false);context.LineTo(p2,true,false);context.LineTo(p3,true,false);}别的{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);如果(角度< 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);}否则(角度< 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);}否则(角度<180d + a){context.LineTo(new Point(x-y * t,p2.Y),true,false);context.LineTo(p3,true,false);context.LineTo(p0,true,false);}否则,如果(角度< 360d-a){context.LineTo(new Point(p0.X,y + x/t),true,false);context.LineTo(p0,true,false);}别的{context.LineTo(new Point(x + y * t,p0.Y),true,false);}context.LineTo(new Point(x,p0.Y),true,false);}}}}} 

I am trying to create a 3..2..1 countdown in the form of a user control. Something like this. My Idea was to create two rectangles on top of each other, one light and one dark and have a radial circle as the clipper for the dark rectangle. The radial circle would have Angle property animated so it would turn around.

I found an implementation of the radial circle and bound the Clip property of the rectangle on the RenderedGeometry property of my circle. Here is the result :

The red stroke is the shape of my clipper. This seems to be an odd behavior of the clipping but I sort of understand it but I would like to know if there was a way of going around the fact that my clipped object seems to use the RenderedGeometry in a weird way.

Edit 1 : The effect I am looking for http://www.youtube.com/watch?v=9FPHTo5V2BQ

解决方案

The simple derived Shape control shown below draws the countdown rectangle. You have to set its Fill (and perhaps Stroke), Width, Height and Angle properties, and you can animate Angle from 0 to 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);
                }
            }
        }
    }
}

这篇关于WPF裁剪具有形状的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆