Little Painter Step by Step-Day 6

来源:互联网 发布:ed2k协议软件下载 编辑:程序博客网 时间:2024/06/07 06:24
 

第六天:(目标:用Command方式实现Display

今天我们要在Components中用Command的方式实现Display,我们首先创建两个工程DisplayAPIDisplayImp。可以设想,我们会使用各种各样的Command,如DrawLineCommandDrawCircleCommand等等,为了能统一的管理这些Command,使得它们能被集中处理,我们需要给它们一个基类ADisplayCommand,这个类从AUndoableCommand继承,由于我们是使用GDI+绘图,所以ADisplayCommand定义如下

public abstract class ADisplayCommand : AUndoableCommand

    {

        public Graphics CurrrentGraphics

        {

            get { return mGraphics; }

            set { mGraphics = value; }

        }

 

        protected Graphics mGraphics;

    }

我们还需要一个DisplayManager来管理这些display commands

public class DisplayManager

    {

        private static List<ADisplayCommand> mDisplayCommandList = new List<ADisplayCommand>();

 

        public static void AddDisplayItem(ADisplayCommand command)

        {

            mDisplayCommandList.Add(command);

        }

 

        public static Boolean RemoveDisplayItem(ADisplayCommand command)

        {

            return mDisplayCommandList.Remove(command);

        }

 

        public static IEnumerator<ADisplayCommand> DisplayItems

        {

            get { return mDisplayCommandList.GetEnumerator(); }

        }

    }

当我们在Canvas上画线时,我们就不用再生成一个DrawInformation了,取而代之,我们将生成一个command,并将该Command添加到DisplayManager中,在Canvas重绘时,我们就遍历DisplayManager的所有Commands并一一执行,这样就达到了和之前使用DrawInformation同样的效果,不同的是,我们使用了抽象类的方式代替了原来的枚举方式,能降低代码的耦合,可以设想,当我以后需要添加画矩形的工具时,在这里我们仅仅从ADisplayCommand继承一个DrawRectangleCommand即可。

接下来是对Canvas的处理,在原来的代码中,我们是使用的Panel作为Canvas,现在我将创建一个从Control类继承的ACanvas类,对于ApplicationForm来说,它只知道ACanvas,至于具体使用的是什么,就由我们自己创建从ACanvas继承的类即可。

public abstract class ACanvas : Control

{

}

public class Canvas : ACanvas

    {

        public Canvas()

        {

            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

            this.SetStyle(ControlStyles.UserPaint, true);

            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

        }

 

        protected override void OnPaint(PaintEventArgs e)

        {

            base.OnPaint(e);

            IEnumerator<ADisplayCommand> displayCommandsEnum = DisplayManager.DisplayItems;

            displayCommandsEnum.Reset();

 

            while (displayCommandsEnum.MoveNext())

            {

                ADisplayCommand command = displayCommandsEnum.Current;

                if (command == null) continue;

 

                command.CurrrentGraphics = e.Graphics;

                if (command.CanExecute(null))

                    command.Execute(null);

            }

        }

    }

最后我们来实现DrawLineCommand

public class DrawLineCommand : ADisplayCommand

    {

        public DrawLineCommand(ACanvas canvas, Pen pen, Point startPoint, Point endPoint)

        {

            if (canvas == null) throw new ArgumentNullException("ACanvas");

            if (pen == null) throw new ArgumentNullException("Pen");

 

            m_Canvas = canvas;

            m_Pen = pen;

            m_StartPoint = startPoint;

            m_EndPoint = endPoint;

        }

 

        public override void Execute(Object parameter)

        {

            mGraphics.DrawLine(m_Pen, m_StartPoint, m_EndPoint);

        }

 

        public override Boolean CanExecute(Object parameter)

        {

            if (m_Canvas == null)

                return false;

            if (m_Pen == null)

                return false;

            if (m_StartPoint.Equals(m_EndPoint))

                return false;

            return true;

        }

 

        public override void Undo()

        {

            DisplayManager.RemoveDisplayItem(this);

            m_Canvas.Invalidate();

        }

 

        public override void Redo()

        {

            DisplayManager.AddDisplayItem(this);

            m_Canvas.Invalidate();

        }

 

        private ACanvas m_Canvas;

        private Pen m_Pen;

        private Point m_StartPoint;

        private Point m_EndPoint;

    }

明天我们将对Tool进行抽象,并对我们的ApplicationForm进行重构