先上图
第一个按钮用了OuterGlowBitmapEffect的效果,第二个按钮用了广泛推荐的DropShadowEffect,第三个按钮用了我自己写的OuterGlowAdorner。
<UniformGrid>
<UniformGrid.Resources>
<Style TargetType="Button">
<Style.Setters>
<Setter Property="Margin" Value="20"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Height" Value="100"/>
</Style.Setters>
</Style>
</UniformGrid.Resources>
<Button Content="OuterGlowBitmapEffect">
<Button.BitmapEffect>
<OuterGlowBitmapEffect GlowSize="20" Opacity="0.8" />
</Button.BitmapEffect>
</Button>
<Button Content="DropShadowEffect">
<Button.Effect>
<DropShadowEffect BlurRadius="20" ShadowDepth="0" Color="Gold" />
</Button.Effect>
</Button>
<Button Name="adorneredButton" FontStyle="Italic" Content="OuterGlowAdorner"/>
</UniformGrid>
很明显,DropShadowEffect从显示效果上来看并不尽人意。我三者都设置了颜色为金色,20单位,但DropShadowEffect颜色明显和其他人不一样,光晕范围也很小。当设置为绿色或其他颜色时候,这种颜色差别更为明显。
所以我自己写了OuterGlowAdorner,注意,它并不在GPU上运行,所以可能比已经过时的OuterGlowBitmapEffect更花资源。
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
namespace Gqqnbig.Windows.Controls
{
public class OuterGlowAdorner : Adorner
{
public static readonly DependencyProperty GlowSizeProperty =
DependencyProperty.Register("GlowSize", typeof(double), typeof(OuterGlowAdorner), new FrameworkPropertyMetadata(5d, FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty GlowColorProperty =
DependencyProperty.Register("GlowColor", typeof(Color), typeof(OuterGlowAdorner), new FrameworkPropertyMetadata(Colors.Gold, FrameworkPropertyMetadataOptions.AffectsRender, (OnGlowColorChanged)));
static OuterGlowAdorner()
{
SnapsToDevicePixelsProperty.OverrideMetadata(typeof(OuterGlowAdorner), new FrameworkPropertyMetadata(true));
}
static void OnGlowColorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var instance = (OuterGlowAdorner)o;
instance.ltBrush = null;
}
private RadialGradientBrush ltBrush;
private LinearGradientBrush tBrush;
private RadialGradientBrush rtBrush;
private LinearGradientBrush lBrush;
private LinearGradientBrush rBrush;
private RadialGradientBrush lbBrush;
private LinearGradientBrush bBrush;
private RadialGradientBrush rbBrush;
private GradientStop endColor;
private GradientStop startColor;
private PathGeometry ltGeo;
private RectangleGeometry tGeo;
private PathGeometry rtGeo;
private RectangleGeometry lGeo;
private RectangleGeometry rGeo;
private PathGeometry lbGeo;
private RectangleGeometry bGeo;
private PathGeometry rbGeo;
public OuterGlowAdorner(UIElement adornedElement)
: base(adornedElement)
{ }
public double GlowSize
{
get { return (double)GetValue(GlowSizeProperty); }
set { SetValue(GlowSizeProperty, value); }
}
public Color GlowColor
{
get { return (Color)GetValue(GlowColorProperty); }
set { SetValue(GlowColorProperty, value); }
}
protected override void OnRender(DrawingContext drawingContext)
{
if (ltBrush == null)
CreateBrushes();
if (ltGeo == null)
CreateGeometries();
drawingContext.DrawGeometry(ltBrush, null, ltGeo);
drawingContext.DrawGeometry(tBrush, null, tGeo);
drawingContext.DrawGeometry(rtBrush, null, rtGeo);
drawingContext.DrawGeometry(lBrush, null, lGeo);
drawingContext.DrawGeometry(rBrush, null, rGeo);
drawingContext.DrawGeometry(lbBrush, null, lbGeo);
drawingContext.DrawGeometry(bBrush, null, bGeo);
drawingContext.DrawGeometry(rbBrush, null, rbGeo);
}
private void CreateGeometries()
{
Size arcSize = new Size(GlowSize, GlowSize);
Size adornedSize = AdornedElement.RenderSize;
//上层
ltGeo = new PathGeometry();
var fig = new PathFigure();
fig.StartPoint = new Point(0, -GlowSize);
fig.Segments.Add(new ArcSegment
{
Size = arcSize,
SweepDirection = SweepDirection.Counterclockwise,
Point = new Point(-GlowSize, 0),
//IsStroked = false
});
fig.Segments.Add(new LineSegment(new Point(0, 0), false));
ltGeo.Figures.Add(fig);
tGeo = new RectangleGeometry();
tGeo.Rect = new Rect(new Point(0, -GlowSize), new Size(adornedSize.Width, GlowSize));
rtGeo = new PathGeometry();
fig = new PathFigure();
fig.StartPoint = new Point(adornedSize.Width, -GlowSize);
fig.Segments.Add(new ArcSegment
{
Size = arcSize,
SweepDirection = SweepDirection.Clockwise,
Point = new Point(adornedSize.Width + GlowSize, 0),
//IsStroked = false
});
fig.Segments.Add(new LineSegment(new Point(adornedSize.Width, 0), false));
rtGeo.Figures.Add(fig);
//中层
lGeo = new RectangleGeometry();
lGeo.Rect = new Rect(new Point(-GlowSize, 0), new Size(GlowSize, adornedSize.Height));
rGeo = new RectangleGeometry();
rGeo.Rect = new Rect(new Point(adornedSize.Width, 0), new Size(GlowSize, adornedSize.Height));
//下层
lbGeo = new PathGeometry();
fig = new PathFigure();
fig.StartPoint = new Point(-GlowSize, adornedSize.Height);
fig.Segments.Add(new ArcSegment
{
Size = arcSize,
SweepDirection = SweepDirection.Counterclockwise,
Point = new Point(0, adornedSize.Height + GlowSize),
});
fig.Segments.Add(new LineSegment(new Point(0, adornedSize.Height), false));
lbGeo.Figures.Add(fig);
bGeo = new RectangleGeometry();
bGeo.Rect = new Rect(new Point(0, adornedSize.Height), new Size(adornedSize.Width, GlowSize));
rbGeo = new PathGeometry();
fig = new PathFigure();
fig.StartPoint = new Point(adornedSize.Width, adornedSize.Height + GlowSize);
fig.Segments.Add(new ArcSegment
{
Size = arcSize,
SweepDirection = SweepDirection.Counterclockwise,
Point = new Point(adornedSize.Width + GlowSize, adornedSize.Height),
//IsStroked = false
});
fig.Segments.Add(new LineSegment(new Point(adornedSize.Width, adornedSize.Height), false));
rbGeo.Figures.Add(fig);
//冻结所有图形
ltGeo.Freeze();
tGeo.Freeze();
rtGeo.Freeze();
lGeo.Freeze();
rGeo.Freeze();
lbGeo.Freeze();
bGeo.Freeze();
rGeo.Freeze();
}
private void CreateBrushes()
{
startColor = new GradientStop(GlowColor, 0);
startColor.Freeze();
endColor = new GradientStop(Colors.Transparent, 1);
endColor.Freeze();
//上层
ltBrush = new RadialGradientBrush();
ltBrush.Center = new Point(1, 1);
ltBrush.GradientOrigin = new Point(1, 1);
ltBrush.RadiusX = 1;
ltBrush.RadiusY = 1;
ltBrush.GradientStops.Add(startColor);
ltBrush.GradientStops.Add(endColor);
tBrush = new LinearGradientBrush();
tBrush.StartPoint = new Point(0.5, 1);
tBrush.EndPoint = new Point(0.5, 0);
tBrush.GradientStops.Add(startColor);
tBrush.GradientStops.Add(endColor);
rtBrush = new RadialGradientBrush();
rtBrush.Center = new Point(0, 1);
rtBrush.GradientOrigin = new Point(0, 1);
rtBrush.RadiusX = 1;
rtBrush.RadiusY = 1;
rtBrush.GradientStops.Add(startColor);
rtBrush.GradientStops.Add(endColor);
//中层
lBrush = new LinearGradientBrush();
lBrush.StartPoint = new Point(1, 0.5);
lBrush.EndPoint = new Point(0, 0.5);
lBrush.GradientStops.Add(startColor);
lBrush.GradientStops.Add(endColor);
rBrush = new LinearGradientBrush();
rBrush.StartPoint = new Point(0, 0.5);
rBrush.EndPoint = new Point(1, 0.5);
rBrush.GradientStops.Add(startColor);
rBrush.GradientStops.Add(endColor);
//下层
lbBrush = new RadialGradientBrush();
lbBrush.Center = new Point(1, 0);
lbBrush.GradientOrigin = new Point(1, 0);
lbBrush.RadiusX = 1;
lbBrush.RadiusY = 1;
lbBrush.GradientStops.Add(startColor);
lbBrush.GradientStops.Add(endColor);
bBrush = new LinearGradientBrush();
bBrush.StartPoint = new Point(0.5, 0);
bBrush.EndPoint = new Point(0.5, 1);
bBrush.GradientStops.Add(startColor);
bBrush.GradientStops.Add(endColor);
rbBrush = new RadialGradientBrush();
rbBrush.Center = new Point(0, 0);
rbBrush.GradientOrigin = new Point(0, 0);
rbBrush.RadiusX = 1;
rbBrush.RadiusY = 1;
rbBrush.GradientStops.Add(startColor);
rbBrush.GradientStops.Add(endColor);
//冻结所有笔刷
ltBrush.Freeze();
tBrush.Freeze();
rtBrush.Freeze();
lBrush.Freeze();
rBrush.Freeze();
lbBrush.Freeze();
bBrush.Freeze();
rbBrush.Freeze();
}
}
}
其实呢。。DropShadowEffect颜色偏淡的问题可以用decorator等容器,套两个DropShadowEffect,这样颜色就浓了。颜色偏移的问题可以调整GlowColor来解决。