WPF标注装饰器

标注

在许多地方我们都会用到标注,比如在画图中:

在Office中:

在Foxit Reader中:

在Blend中:

等等。

简介

以前,因项目上需要做标注,简单找了一下,没发现适合要求的控件(包括Blend中的标注,标注的两个点距离是固定的)。所以自己简单的写了一个。后来又私下修改了几次,基本完成了圆角矩形的标注。

效果图如下:

对应的XAML代码如下:

<local:CalloutDecorator Margin="5" AnchorOffsetX="150" AnchorOffsetY="50"
                        Background="Purple" BorderBrush="Red" BorderThickness="10,20,30,40"
                        CornerRadius="10,20,30,40" Dock="Left" FirstOffset="110"
                        Padding="40" SecondOffset="130">
    <Border Background="Yellow" />
</local:CalloutDecorator>

支持设置锚点(AnchorOffsetX和AnchorOffsetY)、与锚点相对应的两个点的坐标(FirstOffset

和SecondOffset)、朝向(Dock)、圆角信息(CornerRadius)、边框信息(BorderThickness、BorderBrush)、保留空间(Padding)、背景(Background)。

设置各项参数时需要注意,不能让与锚点相对应的两个点的坐标都边框以内,否则会产生奇怪的效果。

但是好在我们一般情况下都不会将边框设的过大,而将两个点设置的较小。

代码

代码中重载了WPF三个重要过程,测量(MeasureOverride)、布局(ArrangeOverride)、绘制(OnRender)。为了提高绘制效率,使用了缓存。代码较简单,也有注释,就不再多说了。

namespace YiYan127.WPF.Decorator
{
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;

    /// <summary>
    /// 标注式装饰器
    /// </summary>
    public class CalloutDecorator : Border
    {
        #region Fields

        #region DependencyProperty

        public static readonly DependencyProperty DockProperty = DependencyProperty.Register(
            "Dock",
            typeof(Dock),
            typeof(CalloutDecorator),
            new FrameworkPropertyMetadata(Dock.Bottom, Refresh));

        public static readonly DependencyProperty AnchorOffsetXProperty = DependencyProperty.Register(
            "AnchorOffsetX",
            typeof(double),
            typeof(CalloutDecorator),
            new FrameworkPropertyMetadata(20.0, Refresh),
            DoubleGreatterThanZero);

        public static readonly DependencyProperty AnchorOffsetYProperty = DependencyProperty.Register(
            "AnchorOffsetY",
            typeof(double),
            typeof(CalloutDecorator),
            new FrameworkPropertyMetadata(20.0, Refresh),
            DoubleGreatterThanZero);

        public static readonly DependencyProperty FirstOffsetProperty = DependencyProperty.Register(
            "FirstOffset",
            typeof(double),
            typeof(CalloutDecorator),
            new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsArrange),
            DoubleGreatterThanZero);

        public static readonly DependencyProperty SecondOffsetProperty = DependencyProperty.Register(
            "SecondOffset",
            typeof(double),
            typeof(CalloutDecorator),
            new FrameworkPropertyMetadata(20.0, FrameworkPropertyMetadataOptions.AffectsArrange),
            DoubleGreatterThanZero);

        #endregion DependencyProperty

        /// <summary>
        /// 刷新选项
        /// </summary>
        private const FrameworkPropertyMetadataOptions Refresh =
            FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender
            | FrameworkPropertyMetadataOptions.AffectsArrange;

        /// <summary>
        /// 是否为Callout模式,为false的话,表示border模式
        /// </summary>
        private bool isCalloutMode;

        /// <summary>
        /// 背景的缓存
        /// </summary>
        private StreamGeometry backgroundGeometryCache;

        /// <summary>
        /// 标注的缓存
        /// </summary>
        private StreamGeometry calloutGeometryCache;

        #endregion Fields

        #region Properties

        /// <summary>
        /// 引线朝向(左、上、右、下)
        /// </summary>
        public Dock Dock
        {
            get { return (Dock)GetValue(DockProperty); }
            set { this.SetValue(DockProperty, value); }
        }

        /// <summary>
        /// X方向的锚点偏移(针对子控件)
        /// </summary>
        public double AnchorOffsetX
        {
            get { return (double)GetValue(AnchorOffsetXProperty); }
            set { this.SetValue(AnchorOffsetXProperty, value); }
        }

        /// <summary>
        /// Y方向的锚点偏移(针对子控件)
        /// </summary>
        public double AnchorOffsetY
        {
            get { return (double)GetValue(AnchorOffsetYProperty); }
            set { this.SetValue(AnchorOffsetYProperty, value); }
        }

        /// <summary>
        /// 在对应的轴上第一个偏移位置
        /// </summary>
        public double FirstOffset
        {
            get { return (double)GetValue(FirstOffsetProperty); }
            set { this.SetValue(FirstOffsetProperty, value); }
        }

        /// <summary>
        /// 在对应的轴上的第二个偏移位置
        /// </summary>
        public double SecondOffset
        {
            get { return (double)GetValue(SecondOffsetProperty); }
            set { this.SetValue(SecondOffsetProperty, value); }
        }

        #endregion Properties

        #region Overrides

        /// <summary>
        /// 重载测量过程
        /// </summary>
        /// <param name="constraint">约束</param>
        /// <returns>需要的大小</returns>
        protected override Size MeasureOverride(Size constraint)
        {
            this.isCalloutMode = (this.Child != null) && (!IsZero(this.AnchorOffsetX) && (!IsZero(this.AnchorOffsetY)));

            if (!this.isCalloutMode)
            {
                return base.MeasureOverride(constraint);
            }

            Size borderSize = GetDesiredSize(this.BorderThickness);
            Size paddingSize = GetDesiredSize(this.Padding);

            // 最少需要的大小
            var basicSize = new Size(borderSize.Width + paddingSize.Width, borderSize.Height + paddingSize.Height);

            // 计算需要的实际大小
            switch (Dock)
            {
                case Dock.Left:
                case Dock.Right:
                    {
                        // 宽度不能小于0
                        double availableWidth = Math.Max(0, constraint.Width - basicSize.Width - this.AnchorOffsetX);
                        var availableSize = new Size(availableWidth, Math.Max(0.0, constraint.Height - basicSize.Height));

                        this.Child.Measure(availableSize);
                        Size desiredSize = this.Child.DesiredSize;

                        return new Size(
                            desiredSize.Width + basicSize.Width + this.AnchorOffsetX,
                            desiredSize.Height + basicSize.Height);
                    }

                case Dock.Top:
                case Dock.Bottom:
                    {
                        double availableHeight = Math.Max(0, constraint.Height - basicSize.Height - this.AnchorOffsetY);
                        var availableSize = new Size(Math.Max(0.0, constraint.Width - basicSize.Width), availableHeight);

                        this.Child.Measure(availableSize);
                        Size desiredSize = this.Child.DesiredSize;

                        return new Size(
                            desiredSize.Width + basicSize.Width,
                            desiredSize.Height + basicSize.Height + this.AnchorOffsetY);
                    }
            }

            return basicSize;
        }

        /// <summary>
        /// 重载布局过程
        /// </summary>
        /// <param name="finalSize">可用的布局大小</param>
        /// <returns>布局大小</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            if (!this.isCalloutMode)
            {
                return base.ArrangeOverride(finalSize);
            }

            var boundaryRect = new Rect(finalSize);
            var outterRect = new Rect();

            switch (Dock)
            {
                #region 根据不同的Dock进行处理

                case Dock.Left:
                    {
                        outterRect = DeflateRect(boundaryRect, new Thickness(this.AnchorOffsetX, 0, 0, 0));
                        break;
                    }

                case Dock.Right:
                    {
                        outterRect = DeflateRect(boundaryRect, new Thickness(0, 0, this.AnchorOffsetX, 0));
                        break;
                    }

                case Dock.Top:
                    {
                        outterRect = DeflateRect(boundaryRect, new Thickness(0, this.AnchorOffsetY, 0, 0));
                        break;
                    }

                case Dock.Bottom:
                    {
                        outterRect = DeflateRect(boundaryRect, new Thickness(0, 0, 0, this.AnchorOffsetY));
                        break;
                    }

                #endregion 根据不同的Dock进行处理
            }

            Rect innerRect = DeflateRect(outterRect, this.BorderThickness);
            Rect finalRect = DeflateRect(innerRect, this.Padding);
            this.Child.Arrange(finalRect);

            var innerPoints = new BorderPoints(this.CornerRadius, this.BorderThickness, false);
            if (!IsZero(innerRect.Width) && !IsZero(innerRect.Height))
            {
                var streamGeometry = new StreamGeometry();
                using (StreamGeometryContext streamGeometryContext = streamGeometry.Open())
                {
                    this.GenerateGeometry(streamGeometryContext, innerRect, innerPoints, boundaryRect);
                }

                streamGeometry.Freeze();
                this.backgroundGeometryCache = streamGeometry;
            }
            else
            {
                this.backgroundGeometryCache = null;
            }

            if (!IsZero(outterRect.Width) && !IsZero(outterRect.Height))
            {
                var outterPoints = new BorderPoints(this.CornerRadius, this.BorderThickness, true);
                var streamGeometry = new StreamGeometry();
                using (StreamGeometryContext streamGeometryContext = streamGeometry.Open())
                {
                    this.GenerateGeometry(streamGeometryContext, outterRect, outterPoints, boundaryRect);
                    if (this.backgroundGeometryCache != null)
                    {
                        this.GenerateGeometry(streamGeometryContext, innerRect, innerPoints, boundaryRect);
                    }
                }

                streamGeometry.Freeze();
                this.calloutGeometryCache = streamGeometry;
            }
            else
            {
                this.calloutGeometryCache = null;
            }

            return finalSize;
        }

        /// <summary>
        /// 重载绘制
        /// </summary>
        /// <param name="dc"></param>
        protected override void OnRender(DrawingContext dc)
        {
            if (!this.isCalloutMode)
            {
                base.OnRender(dc);
                return;
            }

            if (this.calloutGeometryCache != null && this.BorderBrush != null)
            {
                dc.DrawGeometry(this.BorderBrush, null, this.calloutGeometryCache);
            }

            if (this.backgroundGeometryCache != null && this.Background != null)
            {
                dc.DrawGeometry(this.Background, null, this.backgroundGeometryCache);
            }
        }

        #endregion Overrides

        #region Private Methods

        /// <summary>
        /// 验证类型为double且大于0
        /// </summary>
        /// <param name="value">值</param>
        /// <returns>数据为double类型且大于0</returns>
        private static bool DoubleGreatterThanZero(object value)
        {
            return (value is double) && ((double)value) > 0;
        }

        /// <summary>
        /// 获取期望的大小
        /// </summary>
        /// <param name="thickness">边框信息</param>
        /// <returns>期望的大小</returns>
        private static Size GetDesiredSize(Thickness thickness)
        {
            return new Size(thickness.Left + thickness.Right, thickness.Top + thickness.Bottom);
        }

        /// <summary>
        /// 返回在矩形中留出边框后的矩形
        /// </summary>
        /// <param name="rt">矩形</param>
        /// <param name="thick">边框</param>
        /// <returns>留出边框后的矩形</returns>
        private static Rect DeflateRect(Rect rt, Thickness thick)
        {
            return new Rect(rt.Left + thick.Left, rt.Top + thick.Top, Math.Max(0.0, rt.Width - thick.Left - thick.Right), Math.Max(0.0, rt.Height - thick.Top - thick.Bottom));
        }

        /// <summary>
        /// 判断一个数是否为0
        /// </summary>
        /// <param name="value">数</param>
        /// <returns>为0返回true,否则返回false</returns>
        private static bool IsZero(double value)
        {
            return Math.Abs(value) < 2.22044604925031E-15;
        }

        /// <summary>
        /// 返回过两点的直线在Y坐标上的X坐标
        /// </summary>
        /// <param name="point1">第一个点</param>
        /// <param name="point2">第二个点</param>
        /// <param name="y">Y坐标</param>
        /// <returns>对应的X坐标</returns>
        private static double CalculateLineX(Point point1, Point point2, double y)
        {
            return point1.X - ((point1.X - point2.X) * (point1.Y - y) / (point1.Y - point2.Y));
        }

        /// <summary>
        /// 返回过两点的直线在X坐标上的Y坐标
        /// </summary>
        /// <param name="point1">第一个点</param>
        /// <param name="point2">第二个点</param>
        /// <param name="x">X坐标</param>
        /// <returns>对应的Y坐标</returns>
        private static double CalculateLineY(Point point1, Point point2, double x)
        {
            return point1.Y - ((point1.X - x) * (point1.Y - point2.Y) / (point1.X - point2.X));
        }

        /// <summary>
        /// 生成形状
        /// </summary>
        /// <param name="ctx">绘制上下文</param>
        /// <param name="rect">绘制所在的矩形</param>
        /// <param name="points">边框绘制点</param>
        /// <param name="boundaryRect">绘制的外边界</param>
        private void GenerateGeometry(StreamGeometryContext ctx, Rect rect, BorderPoints points, Rect boundaryRect)
        {
            var leftTopPt = new Point(points.LeftTop, 0.0);
            var rightTopPt = new Point(rect.Width - points.RightTop, 0.0);
            var topRightPt = new Point(rect.Width, points.TopRight);
            var bottomRightPt = new Point(rect.Width, rect.Height - points.BottomRight);
            var rightBottomPt = new Point(rect.Width - points.RightBottom, rect.Height);
            var leftBottomPt = new Point(points.LeftBottom, rect.Height);
            var bottomLeftPt = new Point(0.0, rect.Height - points.BottomLeft);
            var topLeftPt = new Point(0.0, points.TopLeft);

            if (leftTopPt.X > rightTopPt.X)
            {
                double x = points.LeftTop / (points.LeftTop + points.RightTop) * rect.Width;
                leftTopPt.X = x;
                rightTopPt.X = x;
            }

            if (topRightPt.Y > bottomRightPt.Y)
            {
                double y = points.TopRight / (points.TopRight + points.BottomRight) * rect.Height;
                topRightPt.Y = y;
                bottomRightPt.Y = y;
            }

            if (rightBottomPt.X < leftBottomPt.X)
            {
                double x2 = points.LeftBottom / (points.LeftBottom + points.RightBottom) * rect.Width;
                rightBottomPt.X = x2;
                leftBottomPt.X = x2;
            }

            if (bottomLeftPt.Y < topLeftPt.Y)
            {
                double y2 = points.TopLeft / (points.TopLeft + points.BottomLeft) * rect.Height;
                bottomLeftPt.Y = y2;
                topLeftPt.Y = y2;
            }

            var vector = new Vector(rect.TopLeft.X, rect.TopLeft.Y);
            leftTopPt += vector;
            rightTopPt += vector;
            topRightPt += vector;
            bottomRightPt += vector;
            rightBottomPt += vector;
            leftBottomPt += vector;
            bottomLeftPt += vector;
            topLeftPt += vector;

            ctx.BeginFigure(leftTopPt, true, true);

            if (this.Dock == Dock.Top)
            {
                var secondOutPoint = new Point(this.SecondOffset, this.AnchorOffsetY);
                var firstOutPoint = new Point(this.FirstOffset, this.AnchorOffsetY);
                var calloutPoint = new Point(this.AnchorOffsetX, 0);

                ctx.LineTo(new Point(CalculateLineX(calloutPoint, firstOutPoint, rect.Top), rect.Top), true, false);
                ctx.LineTo(calloutPoint, true, false);
                ctx.LineTo(new Point(CalculateLineX(calloutPoint, secondOutPoint, rect.Top), rect.Top), true, false);
            }

            ctx.LineTo(rightTopPt, true, false);
            double sizeX = rect.TopRight.X - rightTopPt.X;
            double sizeY = topRightPt.Y - rect.TopRight.Y;
            if (!IsZero(sizeX) || !IsZero(sizeY))
            {
                ctx.ArcTo(topRightPt, new Size(sizeX, sizeY), 0.0, false, SweepDirection.Clockwise, true, false);
            }

            if (this.Dock == Dock.Right)
            {
                var secondOutPoint = new Point(boundaryRect.Width - this.AnchorOffsetX, this.SecondOffset);
                var firstOutPoint = new Point(boundaryRect.Width - this.AnchorOffsetX, this.FirstOffset);
                var calloutPoint = new Point(boundaryRect.Width, this.AnchorOffsetY);

                ctx.LineTo(new Point(rect.Right, CalculateLineY(calloutPoint, firstOutPoint, rect.Right)), true, false);
                ctx.LineTo(calloutPoint, true, false);
                ctx.LineTo(new Point(rect.Right, CalculateLineY(calloutPoint, secondOutPoint, rect.Right)), true, false);
            }

            ctx.LineTo(bottomRightPt, true, false);
            sizeX = rect.BottomRight.X - rightBottomPt.X;
            sizeY = rect.BottomRight.Y - bottomRightPt.Y;
            if (!IsZero(sizeX) || !IsZero(sizeY))
            {
                ctx.ArcTo(rightBottomPt, new Size(sizeX, sizeY), 0.0, false, SweepDirection.Clockwise, true, false);
            }

            if (this.Dock == Dock.Bottom)
            {
                var secondOutPoint = new Point(this.SecondOffset, boundaryRect.Height - this.AnchorOffsetY);
                var firstOutPoint = new Point(this.FirstOffset, boundaryRect.Height - this.AnchorOffsetY);
                var calloutPoint = new Point(this.AnchorOffsetX, boundaryRect.Height);

                ctx.LineTo(new Point(CalculateLineX(calloutPoint, secondOutPoint, rect.Bottom), rect.Bottom), true, false);
                ctx.LineTo(calloutPoint, true, false);
                ctx.LineTo(new Point(CalculateLineX(calloutPoint, firstOutPoint, rect.Bottom), rect.Bottom), true, false);
            }

            ctx.LineTo(leftBottomPt, true, false);
            sizeX = leftBottomPt.X - rect.BottomLeft.X;
            sizeY = rect.BottomLeft.Y - bottomLeftPt.Y;
            if (!IsZero(sizeX) || !IsZero(sizeY))
            {
                ctx.ArcTo(bottomLeftPt, new Size(sizeX, sizeY), 0.0, false, SweepDirection.Clockwise, true, false);
            }

            if (this.Dock == Dock.Left)
            {
                var secondOutPoint = new Point(this.AnchorOffsetX, this.SecondOffset);
                var firstOutPoint = new Point(this.AnchorOffsetX, this.FirstOffset);
                var calloutPoint = new Point(0, this.AnchorOffsetY);

                ctx.LineTo(new Point(rect.Left, CalculateLineY(calloutPoint, firstOutPoint, rect.Left)), true, false);
                ctx.LineTo(calloutPoint, true, false);
                ctx.LineTo(new Point(rect.Left, CalculateLineY(calloutPoint, secondOutPoint, rect.Left)), true, false);
            }

            ctx.LineTo(topLeftPt, true, false);
            sizeX = leftTopPt.X - rect.TopLeft.X;
            sizeY = topLeftPt.Y - rect.TopLeft.Y;
            if (!IsZero(sizeX) || !IsZero(sizeY))
            {
                ctx.ArcTo(leftTopPt, new Size(sizeX, sizeY), 0.0, false, SweepDirection.Clockwise, true, false);
            }
        }

        #endregion Private Methods

        /// <summary>
        /// 边框绘制点
        /// </summary>
        private struct BorderPoints
        {
            internal readonly double LeftTop;
            internal readonly double TopLeft;
            internal readonly double TopRight;
            internal readonly double RightTop;
            internal readonly double RightBottom;
            internal readonly double BottomRight;
            internal readonly double BottomLeft;
            internal readonly double LeftBottom;

            /// <summary>
            /// 构造函数
            /// </summary>
            /// <param name="borderCornerRadius">圆角信息</param>
            /// <param name="boderThickness">边框信息</param>
            /// <param name="outer">是否为外部</param>
            internal BorderPoints(CornerRadius borderCornerRadius, Thickness boderThickness, bool outer)
            {
                double halfLeft = 0.5 * boderThickness.Left;
                double halfTop = 0.5 * boderThickness.Top;
                double halfRight = 0.5 * boderThickness.Right;
                double halfBottom = 0.5 * boderThickness.Bottom;
                if (outer)
                {
                    if (IsZero(borderCornerRadius.TopLeft))
                    {
                        this.LeftTop = this.TopLeft = 0.0;
                    }
                    else
                    {
                        this.LeftTop = borderCornerRadius.TopLeft + halfLeft;
                        this.TopLeft = borderCornerRadius.TopLeft + halfTop;
                    }

                    if (IsZero(borderCornerRadius.TopRight))
                    {
                        this.TopRight = this.RightTop = 0.0;
                    }
                    else
                    {
                        this.TopRight = borderCornerRadius.TopRight + halfTop;
                        this.RightTop = borderCornerRadius.TopRight + halfRight;
                    }

                    if (IsZero(borderCornerRadius.BottomRight))
                    {
                        this.RightBottom = this.BottomRight = 0.0;
                    }
                    else
                    {
                        this.RightBottom = borderCornerRadius.BottomRight + halfRight;
                        this.BottomRight = borderCornerRadius.BottomRight + halfBottom;
                    }

                    if (IsZero(borderCornerRadius.BottomLeft))
                    {
                        this.BottomLeft = this.LeftBottom = 0.0;
                    }
                    else
                    {
                        this.BottomLeft = borderCornerRadius.BottomLeft + halfBottom;
                        this.LeftBottom = borderCornerRadius.BottomLeft + halfLeft;
                    }
                }
                else
                {
                    this.LeftTop = Math.Max(0.0, borderCornerRadius.TopLeft - halfLeft);
                    this.TopLeft = Math.Max(0.0, borderCornerRadius.TopLeft - halfTop);
                    this.TopRight = Math.Max(0.0, borderCornerRadius.TopRight - halfTop);
                    this.RightTop = Math.Max(0.0, borderCornerRadius.TopRight - halfRight);
                    this.RightBottom = Math.Max(0.0, borderCornerRadius.BottomRight - halfRight);
                    this.BottomRight = Math.Max(0.0, borderCornerRadius.BottomRight - halfBottom);
                    this.BottomLeft = Math.Max(0.0, borderCornerRadius.BottomLeft - halfBottom);
                    this.LeftBottom = Math.Max(0.0, borderCornerRadius.BottomLeft - halfLeft);
                }
            }
        }
    }
}
时间: 2024-10-27 06:09:51

WPF标注装饰器的相关文章

WPF装饰器

装饰器定义: 装饰器是一种特殊类型的 FrameworkElement,用于向用户提供可视化提示. 对于其他用户,装饰器可用于将功能控点添加到元素中或提供有关控件的状态信息. 装饰器可以在不改变原有的控件结构的基础上将功能控点添加到元素中或在界面元素上提供视觉效果等.如WPF中的光标效果.焦点效果等就是通过装饰器实现的.如图 通过WPF inspector看到的装饰器层及Button的默认Focus效果:             装饰器是一个始终位于装饰元素或装饰元素集合上方的呈现图面,其呈现独

WPF和Expression Blend开发实例:Adorner(装饰器)应用实例

装饰器-- 表示用于修饰 UIElement 的 FrameworkElement 的抽象类 简单来说就是,在不改变一个UIElement结构的情况下,将一个Visual对象加到它上面. 应用举例: 现在我们拥有一个文本框,但是我们需要限定输入的字符串,当输入的是非法字符串的时候,要求将文本框的四周包裹一个红色的边框.通常我们可以用Border将文本框包裹在里面,然后动态地改变它的颜色来实现功能.那么现在我们可以直接在文本框上面加一个装饰器来实现. Adorner类 AdornerLayer类

TypeScript学习笔记(九):装饰器(Decorators)

装饰器简介 装饰器(Decorators)为我们在类的声明及成员上通过元编程语法添加标注提供了一种方式. 需要注意的是:装饰器是一项实验性特性,在未来的版本中可能会发生改变. 若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json里启用experimentalDecorators编译器选项: 1 { 2 "compilerOptions": { 3 "target": "ES5", 4 "experimentalDeco

(十)装饰器模式详解(与IO不解的情缘)

LZ到目前已经写了九个设计模式,回过去看看,貌似写的有点凌乱,LZ后面会尽量改进. 那么本章LZ和各位读友讨论一个与JAVA中IO有着不解情缘的设计模式,装饰器模式. 定义:装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象.                  这一个解释,引自百度百科,我们注意其中的几点. 1,不改变原类文件.                  2,不使用继承.                  3,动

内置函数和装饰器的进阶

30个内置函数及用法: 带key的重点标注: # def wrapper1(func): # def inner1(*args,**kwargs): # print('in wrapper 1,before') # ret = func(*args,**kwargs) #qqxing # print('in wrapper 1,after') # return ret # return inner1 # # def wrapper2(func): #inner1 # def inner2(*ar

设计模式(三)_装饰器模式

上篇学习了策略模式,现在回想下,什么是策略模式,好了.本篇主要介绍装饰器模式,just do it! 什么是装饰器模式 装饰器模式指的是动态的将责任附加到对象上.若要扩展功能,装饰器模式提供了比继承更弹性的替代方案. 如何使用装饰器模式 老王来到商场买衣服,需要买衣服,裤子,帽子...... public class Wang { public void show(){ System.out.println("我穿上衣服,累计花费100元"); System.out.println(&

20181122_C#中AOP初探_装饰器模式的AOP_Remoting实现AOP_Castle实现AOP

一.   什么是AOP: a)         AOP是面向切面编程; 就像oop一样, 它也是一种编程思想; i.    Oop思想→一切皆对象, 对象交互组成功能, 功能叠加组成模块, 模块叠加组成系统; 如果把一个个的类比喻成一个个砖头, 那么系统就是一个房子; 房子是由一块块砖头构成, 所以面向对象非常适合做大型系统; 但是面向对象的在应对系统扩展的时候, 就显得力不从心; 如果砖块需要发生变化, 则就会牵扯到很多地方; 因为面向对象是静态的, 内部就是强耦合的关系; 虽然设计模式可以解

Adorner 装饰器

装饰器 Adorner 装饰器是WPF中较为常用的技术之一,也是不同于XAML的技术. 较为特殊. 特殊于装饰器全部由C#构成,不同于ControlTenmpate和Style的元素. 装饰器在某些方面能够简化前两者的代码量. 现在简单的说一下装饰器的入门用法(通常用法和附加属性一起使用) Adorner是一个抽象类. 由于显示装饰器的方式有两种 直接装载现有WPF控件 绘制控件 直接装载现有控件: 这种方法需要重载四个Adorner方法 GetVisualChild //获取Visual的子控

Flask--视图增加多装饰器

一:问题:添加多个装饰器,抛异常 在Flask中如果按照普通的方法加装饰器,看上去是没有问题.他会抛出一个异常 from flask import Flask, render_template, redirect, request, session app = Flask(__name__) app.debug = True app.secret_key = '123' @app.route('/') def home(): return 'hello word' def wapper(func