如何在WPF中的几何图形中绘制阴影效果

How to draw dropshadow effect in a geometry in WPF

我正在 Canvas 中绘制以下 Shape

我想在通过更改其颜色(简单的部分)和绘图来选择它时突出显示它周围有一个小光环

这就是我使用 SASS 的方式:http://codepen.io/aaromnido/pen/zKvAwd/

我如何在 WPF 中绘图?请记住,我正在使用 Shape's OnRender 方法绘图。

无论您的控件进入 Highlighted 状态的触发器是什么,在该触发器中只需设置 Effect 属性。对于我的测试,"trigger" 是 属性:

    public static readonly DependencyProperty ShowShadowProperty =
        DependencyProperty.Register ("ShowShadow", typeof (bool), typeof (TestShape), new PropertyMetadata (false, ShowShadowChanged));

    public bool ShowShadow
    {
        get { return (bool)GetValue (ShowShadowProperty); }
        set { SetValue (ShowShadowProperty, value); }
    }

    private static void ShowShadowChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((TestShape)d).OnShowShadow ();
    }

    private void OnShowShadow ()
    {
        if (ShowShadow)
        {
            Effect = new DropShadowEffect { Direction = 0, ShadowDepth = 20, BlurRadius = 33, Opacity = 1, Color = Colors.Black};
        }
        else
        {
            Effect = null;
        }
    }

这意味着您无需在 OnRender 中执行任何操作。

  1. 在构造函数中设置一些默认值。

  2. 其中一个默认值是 Shape.Effect,因为它将在 MouseEnter 事件上进行动画处理。

  3. 为 Normal 和 MouseEnter 场景构造 VisualStates

  4. 使用 MouseEnterMouseLeave 事件处理程序中的 VisualStateManager.GoToElementState() 更改元素的 VisualState

您可以使用 DP 公开各种属性以进行自定义。

NewShape.cs

using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows;
using System.Windows.Media.Effects;

namespace WpfWhosebug.NewShape
{
    public class CNewShape : Shape
    {
        public CNewShape()
        {
            // setting the defaults
            this.Width = 40;
            this.Height = 40;
            this.Stroke = new SolidColorBrush() { Color = Colors.Red };
            this.StrokeThickness = 5;
            this.Effect = new DropShadowEffect() {

                Color = Colors.Transparent,
                BlurRadius = 1,
                Direction = -150,
                ShadowDepth = 1            
            };

            // constructing the VisualStates
            _constructVisualStates();

            // event handlers
            this.MouseEnter += CNewShape_MouseEnter;
            this.MouseLeave += CNewShape_MouseLeave;
        }

        #region EventHandlers
        void CNewShape_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            VisualStateManager.GoToElementState(this, "VSNormal", false);
        }

        void CNewShape_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            VisualStateManager.GoToElementState(this, "VSMouseEnter", false);
        }
        #endregion

        #region Overrides

        // This needs to be implemented as it is abstract in base class
        GeometryGroup geo = new GeometryGroup();
        protected override Geometry DefiningGeometry
        {
            get { return geo; }
        }

        protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
        {
            Pen pen = new Pen(this.Stroke, StrokeThickness);
            drawingContext.DrawEllipse(Brushes.Transparent, pen, new Point(Width/2, Height/2), 40, 40);

            drawingContext.DrawEllipse(Stroke, null, new Point(Width / 2, Height / 2), 30, 30);
            base.OnRender(drawingContext);
        }
        #endregion

        #region Helpers

        private void _constructVisualStates()
        {         
            VisualStateGroup vsg1 = new VisualStateGroup();

            #region VSNormal (Normal Visual State)
                VisualState stateVSNormal = new VisualState() { Name = "VSNormal" };

                Storyboard sbVSNormal = new Storyboard();
                    ObjectAnimationUsingKeyFrames oa = new ObjectAnimationUsingKeyFrames();
                    Storyboard.SetTargetProperty(oa, new PropertyPath("Effect"));
                    DiscreteObjectKeyFrame dokf = new DiscreteObjectKeyFrame(null);
                    oa.KeyFrames.Add(dokf);
                    sbVSNormal.Children.Add(oa);

                stateVSNormal.Storyboard = sbVSNormal;
                vsg1.States.Add(stateVSNormal);
            #endregion                       

            #region VSMouseEnter (MouseEnter Visual State)
                VisualState stateVSMouseEnter = new VisualState() { Name = "VSMouseEnter" };

                Storyboard sbVSMouseEnter = new Storyboard();

                    ColorAnimation caStrokeColor = new ColorAnimation();
                    caStrokeColor.To = (Color)ColorConverter.ConvertFromString("#FF24BCDE");
                    Storyboard.SetTargetProperty(caStrokeColor, new PropertyPath("(Shape.Stroke).(SolidColorBrush.Color)"));
                    sbVSMouseEnter.Children.Add(caStrokeColor);

                    ColorAnimation caEffectColor = new ColorAnimation();
                    caEffectColor.To = (Color)ColorConverter.ConvertFromString("#FFA4E1F3");
                    Storyboard.SetTargetProperty(caEffectColor, new PropertyPath("(Shape.Effect).(Color)"));
                    sbVSMouseEnter.Children.Add(caEffectColor);

                    DoubleAnimation daBlurRadius = new DoubleAnimation();
                    daBlurRadius.To = 10;
                    Storyboard.SetTargetProperty(daBlurRadius, new PropertyPath("(Shape.Effect).(BlurRadius)"));
                    sbVSMouseEnter.Children.Add(daBlurRadius);

                    DoubleAnimation daDirection = new DoubleAnimation();
                    daDirection.To = -190;
                    Storyboard.SetTargetProperty(daDirection, new PropertyPath("(Shape.Effect).(Direction)"));
                    sbVSMouseEnter.Children.Add(daDirection);              

                stateVSMouseEnter.Storyboard = sbVSMouseEnter;
                vsg1.States.Add(stateVSMouseEnter);
            #endregion

            VisualStateManager.GetVisualStateGroups(this).Add(vsg1);
        }

        #endregion
    }
}

用法

 <local:CNewShape Canvas.Left="70" Canvas.Top="52" Stroke="#FF374095" StrokeThickness="10" Width="100" Height="100" />

输出

图像质量差。在屏幕上实际输出看起来不错。