WPF裁剪具有形状 [英] WPF Clipping with a shape
问题描述
我正在尝试以用户控件的形式创建3..2..1倒计时.类似于
下面显示的简单的派生Shape控件绘制了倒数矩形.您必须设置其 Fill
(也许是 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屋!