Netron应用实战系列(2)——Netron基础类介绍
在使用Netron之前,我们要先来了解一下Netron的三个关键类:Shape、Connection、Connector。您可以在 NetronGraphLibrary文件夹下发现他们。这三个类均继承自Entity类。下面我们简要介绍Entity类的基本模块,先看Entity 类的代码。
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Printing;
using System.IO;
using System.Security;
using System.Security.Permissions;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using Netron.GraphLib.UI;
using Netron.GraphLib.Interfaces;
using Netron.GraphLib.Attributes;
using Netron.GraphLib.Configuration;
namespace Netron.GraphLib
{
/// <summary>
/// Abstract base class for everything that participates in the diagram/graph (connection, connector)
/// </summary>
[Serializable] public abstract class Entity : IEntity, IDisposable, ISerializable
{
#region Events
/// <summary>
/// Occurs when the mouse is pressed on this entity
/// </summary>
public event MouseEventHandler OnMouseDown;
/// <summary>
/// Occurs when the mouse is released while above this entity
/// </summary>
public event MouseEventHandler OnMouseUp;
/// <summary>
/// Occurs when the mouse is moved while above this entity
/// </summary>
public event MouseEventHandler OnMouseMove;
#endregion
#region Fields
/// <summary>
/// the layer to which the entity belongs,
/// the default layer is a static unique layer defined in the GraphAbstract.
/// </summary>
private GraphLayer mLayer;
/// <summary>
/// volatile all-purpose tag
/// </summary>
[NonSerialized] private object mTag;
/// <summary>
/// whether to recalculate the shape size, speed up the rendering
/// </summary>
private bool mRecalculateSize ;
/// <summary>
/// the property bag
/// </summary>
[NonSerialized] private PropertyBag mBag;
/// <summary>
/// default blue mPen, speeds up rendering
/// Note that the Pen is not serialzable!
/// </summary>
[NonSerialized] private Pen mBluePen;
/// <summary>
/// default black mPen, speeds up rendering
/// </summary>
[NonSerialized] private Pen mBlackPen;
/// <summary>
/// the mPen\'s width
/// </summary>
private float mPenWidth = 1F;
/// <summary>
/// default mPen
/// </summary>
[NonSerialized] private Pen mPen;
/// <summary>
/// whether the entity is reset
/// </summary>
private bool mIsGuiReset;
/// <summary>
/// the font family
/// </summary>
private string mFontFamily = "Verdana";
/// <summary>
/// whether the entity is selected
/// </summary>
private bool mIsSelected;
/// <summary>
/// whether this entity is being hovered
/// </summary>
private bool mIsHovered ;
/// <summary>
/// the unique identitfier
/// </summary>
private Guid mUID ;
/// <summary>
/// mText or label
/// </summary>
private string mText = "[Not set]";
/// <summary>
/// whether to show the mText label
/// </summary>
private bool mShowLabel = true;
/// <summary>
/// the default mText color
/// </summary>
private Color mTextColor = Color.Black;
/// <summary>
/// the default font size in points
/// </summary>
private float mFontSize = 7.8F;
/// <summary>
/// the default font for entities
/// </summary>
private Font mFont;
/// <summary>
/// the mSite of the entity
/// </summary>
[NonSerialized] private IGraphSite mSite;
#endregion
#region Properties
/// <summary>
/// Gets or sets the pen-object to paint and draw
/// </summary>
public Pen Pen
{
get{return mPen;}
set{mPen = value;}
}
/// <summary>
/// Gets the property-bag
/// </summary>
/// <remarks>The bag acts as a proxy-object for the properties and his part of the propertybag mechanism.</remarks>
protected PropertyBag Bag
{
get{return mBag;}
}
/// <summary>
/// Gets or sets whether the next painting roun will have to recalculate the size of the entity
/// </summary>
protected bool RecalculateSize
{
get{return mRecalculateSize;}
set{mRecalculateSize = value;}
}
/// <summary>
/// Gets the default black mPen for drawing text and lines
/// </summary>
protected Pen BlackPen
{
get{return mBlackPen;}
}
/// <summary>
/// Gets or sets the font-family used by derived class to draw and paint on the canvas
/// </summary>
protected virtual string FontFamily
{
get{return mFontFamily;}
set{mFontFamily = value;}
}
/// <summary>
/// Gets the layer ths shape is on. If null, the shape is in the default layer.
/// </summary>
/// <remarks>User the SetLayer() method to set or change the layer.
/// </remarks>
public GraphLayer Layer
{
get
{
return mLayer;
}
}
/// <summary>
/// Gets or sets a general purpose tag object
/// </summary>
public object Tag
{
get{return mTag;}
set{mTag = value;}
}
/// <summary>
/// Gets or sets the mPen width
/// </summary>
[GraphMLData]public float PenWidth
{
get{return mPenWidth;}
set{mPenWidth = value;}
}
/// <summary>
/// Gets or sets whether the shape label should be shown.
/// </summary>
[GraphMLData]public virtual bool ShowLabel
{
get
{
return mShowLabel;
}
set
{
mShowLabel=value; this.Invalidate();
}
}
/// <summary>
/// Allows to view/change the properties of the shape, most probably on double-clicking it.
/// </summary>
public virtual PropertyBag Properties
{
get{return mBag;}
}
/// <summary>
/// Gets or sets the entity label
/// </summary>
[GraphMLData]public virtual string Text
{
get
{
return mText;
}
set
{
if (value!=null) mText=value;
}
}
/// <summary>
/// Gets or sets the mSite of the entity
/// </summary>
public IGraphSite Site
{
get{return mSite;}
set{mSite = value;}
}
/// <summary>
/// Tells wether the entity (shape) is selected
/// </summary>
public virtual bool IsSelected
{
set { Invalidate(); mIsSelected = value; Invalidate(); }
get { return mIsSelected; }
}
/// <summary>
/// Gets or sets whether the entity\'s UID is reset
/// </summary>
/// <remarks>USed in the cotext of copy/paste</remarks>
protected internal virtual bool IsGuiReset
{
get{return mIsGuiReset;}
set{mIsGuiReset = value;}
}
/// <summary>
/// Gives true if the mouse is hovering over this entity
/// </summary>
protected internal virtual bool IsHovered
{
set { Invalidate(); mIsHovered = value; Invalidate(); }
get { return mIsHovered; }
}
/// <summary>
/// Gets or sets the mText color
/// </summary>
public virtual Color TextColor
{
get
{
return mTextColor;
}
set
{
mTextColor=value;
}
}
/// <summary>
/// Gets or sets the font size of the mText
/// </summary>
protected virtual float FontSize
{
get
{
return mFontSize;
}
set
{
mFontSize=value;
}
}
/// <summary>
/// Gets or sets the font to be used when drawing text-data
/// </summary>
protected Font Font
{
get{return this.mFont;}
set
{
this.mFont = value;
this.mFontFamily = value.FontFamily.ToString();
this.mFontSize = value.Size;
}
}
/// <summary>
/// Gets or sets the unique identifier for the shape.
/// </summary>
public Guid UID
{
get
{
return mUID;
}
set{mUID = value;}
}
/// <summary>
/// Gets the Summary for this entity
/// </summary>
public Summary Summary
{
get
{
return this.Site.GetSummary(this);
}
}
/// <summary>
/// Gets the tracker of the entity
/// </summary>
public virtual Tracker Tracker
{
get{return null;}
set{}
}
#endregion
#region Constructors
/// <summary>
/// Constructor for the entity class, initializes a new GUID for the entity
/// </summary>
protected Entity()
{
InitEntity();
}
/// <summary>
/// Creates a new entity, specifying the mSite
/// </summary>
/// <param name="site"></param>
protected Entity(IGraphSite site)
{
InitEntity();
this.mSite = site;
}
/// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected Entity(SerializationInfo info, StreamingContext context)
{
InitEntity();
//overwrite some members with the serialized data
this.mUID = new Guid(info.GetString("mUID"));
this.mText = info.GetString("mText");
this.mShowLabel = info.GetBoolean("mShowLabel");
this.mTextColor = (Color) info.GetValue("mTextColor",typeof(Color));
try
{
this.mFont = (Font) info.GetValue("mFont", typeof(Font));
}
catch
{
//font is set by default in the member definition
}
//this.mIsSelected = info.GetBoolean("mIsSelected");
}
#endregion
#region Methods
/// <summary>
/// IDispose implementation
/// </summary>
public void Dispose()
{
this.mFont.Dispose();
this.mPen.Dispose();
this.mBlackPen.Dispose();
this.mBluePen.Dispose();
}
/// <summary>
/// Sets the layer the entity belongs to
/// </summary>
/// <param name="layer"></param>
protected virtual void SetLayer(GraphLayer layer)
{
mLayer = layer;
return;
}
/// <summary>
/// Sets the shape in a layer.
/// Use "default" to set the shape in the default layer.
/// </summary>
/// <param name="name"></param>
public void SetLayer(string name)
{
if(name.CompareTo("Default")==0)
{
SetLayer(GraphAbstract.DefaultLayer);
}
else
{
SetLayer(Site.Abstract.Layers[name]);
}
}
/// <summary>
/// Sets the shape in a layer.
/// Layer 0 is the default layer.
/// </summary>
/// <param name="index"></param>
public void SetLayer(int index)
{
if(index==0)
{
SetLayer(GraphAbstract.DefaultLayer);
}
else
{
index--;//the collection starts at 0
SetLayer(Site.Abstract.Layers[index]);
}
}
/// <summary>
/// Determines which properties are accessible via the property grid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void GetPropertyBagValue(object sender, PropertySpecEventArgs e)
{
switch(e.Property.Name)
{
case "Text": e.Value=this.mText;break;
case "ShowLabel": e.Value=this.ShowLabel; break;
}
}
/// <summary>
/// Sets the values passed by the property grid
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected virtual void SetPropertyBagValue(object sender, PropertySpecEventArgs e)
{
switch(e.Property.Name)
{
case "ShowLabel": this.ShowLabel=(bool) e.Value; break;
case "Text":
//use the logic and the constraint of the object that is being reflected
if(e.Value.ToString() != null)
{
this.mText=(string) e.Value;
}
else
MessageBox.Show("Not a valid label","Invalid label",MessageBoxButtons.OK,MessageBoxIcon.Warning);
break;
}
this.Invalidate();
}
/// <summary>
/// When overriden, allows user defined entities to get custom properties
/// </summary>
public virtual void AddProperties()
{
return;
}
/// <summary>
/// Initializes the class. This method is necessary when deserializing since various elements like
/// the Pen cannot be serialized to file and have to be, hence, set after deserialization.
/// </summary>
protected internal virtual void InitEntity()
{
mLayer = GraphAbstract.DefaultLayer;
mBluePen= new Pen(Brushes.DarkSlateBlue,1F);
mBlackPen = new Pen(Brushes.Black,1F);
mUID = Guid.NewGuid();
mRecalculateSize = false;
mFont = new Font(mFontFamily,mFontSize,FontStyle.Regular,GraphicsUnit.Point);
mPen=new Pen(Brushes.Black, mPenWidth);
mLayer = GraphAbstract.DefaultLayer;//everything is initially in the default (static) layer
mBag=new PropertyBag(this);
try
{
mBag.GetValue+=new PropertySpecEventHandler(GetPropertyBagValue);
mBag.SetValue+=new PropertySpecEventHandler(SetPropertyBagValue);
mBag.Properties.Add(new PropertySpec("Text",typeof(string),"Appearance","The text attached to the entity","[Not set]"));
mBag.Properties.Add(new PropertySpec("ShowLabel",typeof(bool),"Appearance","Gets or sets whether the label will be shown."));
// PropertySpec spec=new PropertySpec("MDI children",typeof(string[]));
// spec.Attributes=new Attribute[]{new System.ComponentModel.ReadOnlyAttribute(true)};
// mBag.Properties.Add(spec);
//AddProperties(); //add the user defined shape properties
}
catch(Exception exc) //TODO: catch only those exceptions that you can handle gracefully
{
Trace.WriteLine(exc.Message, "Entity.InitEntity");
}
catch
{
Trace.WriteLine("Non-CLS compliant exception caught.", "Entity.InitEntity");
}
}
/// <summary>
/// creates the actual visual element on screen
/// </summary>
/// <param name="g"></param>
public abstract void Paint(Graphics g);
/// <summary>
/// Gets the cursor for the current position of the mouse
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public abstract Cursor GetCursor(PointF p);
/// <summary>
/// GraphAbstract delete method; deletes the entity from the plex
/// </summary>
internal protected abstract void Delete();
/// <summary>
/// Says wether, for the given rectangle, the underlying shape is contained in it.
/// </summary>
/// <param name="r"></param>
/// <returns></returns>
public abstract bool Hit(RectangleF r);
/// <summary>
/// Invalidating refreshes part or all of a control
/// </summary>
public abstract void Invalidate();
/// <summary>
/// Allows to paints additional things like the clickable elements on shapes
/// independently of the shape\'s design
/// </summary>
/// <param name="g"></param>
public abstract void PaintAdornments(Graphics g);
/// <summary>
/// Paints the tracker of the entity
/// </summary>
/// <param name="g"></param>
public void PaintTracker(Graphics g)
{
if(this.IsSelected) this.Tracker.Paint(g);
}
/// <summary>
/// Regenerates a GUID for this entity
/// </summary>
public void GenerateNewUID()
{
mUID=Guid.NewGuid();
mIsGuiReset=true;
}
/// <summary>
/// Raises the mouse down event
/// </summary>
/// <param name="e"></param>
internal virtual void RaiseMouseDown(MouseEventArgs e)
{
if(OnMouseDown != null) OnMouseDown(this, e);
}
/// <summary>
/// Raises the mouse up event
/// </summary>
/// <param name="e"></param>
internal void RaiseMouseUp(MouseEventArgs e)
{
if(OnMouseUp != null) OnMouseUp(this, e);
}
internal void RaiseMouseMove(MouseEventArgs e)
{
if(OnMouseMove!=null) OnMouseMove(this,e);
}
#endregion
#region ISerializable Members
/// <summary>
/// ISerializable implementation
/// </summary>
/// <param name="info">the serialization info</param>
/// <param name="context">the streaming context</param>
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("mUID",this.mUID.ToString());
info.AddValue("mTextColor",this.mTextColor,typeof(Color));
info.AddValue("mText",this.mText);
info.AddValue("mShowLabel",this.mShowLabel);
info.AddValue("mFont", this.mFont, typeof(Font));
//additional check in case we\'re making a deep copy of a bundle
if(mLayer==null)
info.AddValue("mLayer","Default");
else
info.AddValue("mLayer",this.mLayer.Name);
}
/// <summary>
/// Post-deserialization actions
/// </summary>
public virtual void PostDeserialization()
{
//add the properties
this.AddProperties();
}
#endregion
}
}
可以看到这个基本类多继承接口IEntity, IDisposable, ISerializable。类本身可以做的3个基本鼠标事件支持,以及实体大小等字段,还有序列化方法等等。
下面给出一个三个类的实例图
Shape即为图像所画出的实体,代码太多就不贴了不好意思哈。
字段介绍: 注意看这个字段mRectangle这个字段十分重要,大致作用是shape的本体宿主,你可以通过这个取得shape的坐标以及宽和高。
方法介绍:这里不能不说Paint方法,这个方法是每种shape都要override的方法,其主要作用是绘制图像,不同图像的很大区别也在这个方法的内容不同。
Connection即为图像的连线,代码太多就不贴了不好意思哈
字段介绍 :private Connector mFrom ;private Connector mTo;这两个是Connector(待会介绍这个类)引用,这是保存连线的开始节点和结束节点。private Color mLineColor 连线的颜色。private DashStyle mLineStyle连线的样式,可选值是枚举类型的,比如点,还是实心线等。ConnectionEnd mLineEnd,连线结束头的样子,可选值是枚举类型,例如可选小箭头型。private Tracker mTracker; 这个Tracker类放到下一篇介绍
方法介绍:Invalidate(),刷新自身的方法,另外一个重要的方法是Delete方法。其余方法读者自己可以去研究,我因没有多深入,在此不多说了。
Connector即为图像身边的小灰色方块点,这些点的作用是连线的接头,注意Connection类中含有Connector mFrom 和Connector mTo两个字段。注意Connector仅仅存在于shape类内,自己不可独立存在。也即shape类组合Connector,这里关系类似骑车轮胎和 汽车的关系一样。
Connector也仅仅一个类,如果读者愿意完全可以自己实现一个Connector替换之,下面是它的代码。
using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Printing;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using Netron.GraphLib.Interfaces;
using System.Security;
using System.Security.Permissions;
namespace Netron.GraphLib
{
/**//// <summary>
/// A Connector aka \'connection point\' is the spot on a shape where a line (connection) will attach itself.
/// Lits up when cursor is nearby and can contain in/outflow data that can propagate through the connections.
/// </summary>
/// <remarks>
/// Things you can do:
/// <br>- making the connector blink or flash when hit</br>
/// <br>- show an extensive information box when hovered</br>
/// <br>- attach a status message when hovered</br>
/// <br>- differentiate different connector on their propagation type or their parnet/child relation</br>
///</remarks>
[Serializable] public class Connector : Entity, ISerializable
{
Fields#region Fields
/**//// <summary>
/// gives a little displacement between the connection and the connector
/// </summary>
private float mConnectionShift = 15F;
/**//// <summary>
/// determines the place of the connection shift
/// </summary>
private ConnectorLocation mConnectorLocation = ConnectorLocation.Unknown;
/**//// <summary>
/// the shift point
/// </summary>
private PointF mAdjacentPoint = PointF.Empty;
/**//// <summary>
/// only 1 connection allowed if false
/// </summary>
private bool mAllowMultipleConnections;
/**//// <summary>
/// object this connector belongs to.
/// </summary>
private Shape mBelongsTo;
/**//// <summary>
/// connections attached to this connector
/// </summary>
private ConnectionCollection mConnections;
/**//// <summary>
/// collection of objects that the connector propagates
/// </summary>
private ArrayList mSendList;
/**//// <summary>
/// collection of values/objects that the connector receives from other connectors
/// </summary>
private ArrayList mReceiveList;
/**//// <summary>
/// name of the connector
/// </summary>
private string mName;
/**//// <summary>
/// allow new connections to be launched from this connector
/// </summary>
private bool mAllowNewConnectionsFrom = true;
/**//// <summary>
/// allow new connection to be attached to this connector
/// </summary>
private bool mAllowNewConnectionsTo = true;
#endregion
Properties#region Properties
/**//// <summary>
/// Gets or sets whether to allow new connections to be launched from this connector
/// </summary>
public bool AllowNewConnectionsFrom
{
get{return mAllowNewConnectionsFrom;}
set{mAllowNewConnectionsFrom = value;}
}
/**//// <summary>
/// Gets or sets whether to allow new connections to be attached to this connector
/// </summary>
public bool AllowNewConnectionsTo
{
get{return mAllowNewConnectionsTo;}
set{mAllowNewConnectionsTo = value;}
}
/**//// <summary>
/// Gets or sets the name of the connector.
///
/// </summary>
/// <remarks>
/// This property makes it possible to deserialize a connector, it\'s the only way to find back where a
/// serialized connector came from.
/// </remarks>
public string Name
{
get{return mName;}
set{mName = value;}
}
/**//// <summary>
/// Gets or sets the connection shift with respect to this connector.
/// If the type is \'Omni\' it\'s an offset in the direction of the connection,
/// otherwise it creates a little shift/break in the connection in the direction specified by the
/// ConnectorLocation.
/// </summary>
public float ConnectionShift
{
get{return mConnectionShift;}
set{mConnectionShift = value;}
}
/**//// <summary>
/// The location of the connector
/// </summary>
public PointF Location
{
get{return mBelongsTo.ConnectionPoint(this);}
}
/**//// <summary>
/// Gets or sets whether the connector can have multiple connection attached
/// </summary>
public bool AllowMultipleConnections
{
get{return mAllowMultipleConnections;}
[Browsable(false)] set{mAllowMultipleConnections = value;}
}
/**//// <summary>
/// Gets the connections of a connector
/// </summary>
public ConnectionCollection Connections
{
get
{
return mConnections;
}
}
/**//// <summary>
/// The values/objects that the connector propagates
/// </summary>
public ArrayList Sends
{
get
{
return mSendList;
}
// [Browsable(false)] set
// {
// mSendList= value;
// }
}
/**//// <summary>
/// The values/objects that the connectors receives from other connectors
/// </summary>
public ArrayList Receives
{
get
{
return mReceiveList;
}
// [Browsable(false)]set
// {
// mReceiveList= value;
// }
}
/**//// <summary>
/// The get/Set the ShapeObjects this connector is attached to
/// </summary>
public Shape BelongsTo
{
get
{
return mBelongsTo;
}
[Browsable(false)] set
{
mBelongsTo = value;
}
}
/**//// <summary>
/// Gets or sets the adjacent point which allows to have a little distance between shapes and connections
/// </summary>
public PointF AdjacentPoint
{
get
{
PointF p = mBelongsTo.ConnectionPoint(this);
switch(this.mConnectorLocation)
{
case ConnectorLocation.North: this.mAdjacentPoint= new PointF(p.X,p.Y - mConnectionShift); break;
case ConnectorLocation.East: this.mAdjacentPoint= new PointF(p.X+mConnectionShift,p.Y); break;
case ConnectorLocation.South: this.mAdjacentPoint= new PointF(p.X,p.Y + mConnectionShift); break;
case ConnectorLocation.West: this.mAdjacentPoint= new PointF(p.X-mConnectionShift,p.Y); break;
case ConnectorLocation.Omni: case ConnectorLocation.Unknown: this.mAdjacentPoint= p; break;
}
return mAdjacentPoint;
}
}
/**//// <summary>
/// Gets or sets the location of the connector which will determine where the adjacent point will be
/// </summary>
public ConnectorLocation ConnectorLocation
{
get{return mConnectorLocation;}
[Browsable(false)] set{mConnectorLocation = value;}
}
#endregion
Constructors#region Constructors
/**//// <summary>
/// Constructor of the connector clss
/// </summary>
/// <param name="o">the underlying shape to which the connector belongs</param>
/// <param name="connectorName">the name of the connector</param>
/// <param name="multipleConnections">whether the connector allows multiple connections to be added or connected to it</param>
public Connector(Shape o, string connectorName, bool multipleConnections) : base()
{
mBelongsTo = o;
mName = Text = connectorName;
mConnections = new ConnectionCollection();
mSendList = new ArrayList();
mReceiveList = new ArrayList();
mAllowMultipleConnections = multipleConnections;
}
/**//// <summary>
/// Internal constructor, related to deserialization
/// </summary>
/// <param name="uid"></param>
internal Connector(string uid) : base()
{
this.UID = new Guid(uid);
}
/**//// <summary>
/// Deserialization constructor
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected Connector(SerializationInfo info, StreamingContext context) : base(info, context)
{
this.mName = info.GetString("mName");
this.mAllowMultipleConnections = info.GetBoolean("mAllowMultipleConnections");
this.ConnectorLocation = (ConnectorLocation) info.GetValue("mConnectorLocation", typeof(ConnectorLocation));
this.mConnectionShift = info.GetSingle("mConnectionShift");
try
{
this.mAllowNewConnectionsFrom = info.GetBoolean("mAllowNewConnectionsFrom");
}
catch
{
this.mAllowNewConnectionsFrom = true;
}
try
{
this.mAllowNewConnectionsTo = info.GetBoolean("mAllowNewConnectionsTo");
}
catch
{
this.mAllowNewConnectionsTo = true;
}
mConnections = new ConnectionCollection();
mSendList = new ArrayList();
mReceiveList = new ArrayList();
}
#endregion
Methods#region Methods
/**//// <summary>
/// Implements the abstract method of the Entity class
/// </summary>
/// <param name="g"></param>
public override void PaintAdornments(Graphics g)
{
return;
}
/**//// <summary>
/// Says wether the given RectangleF is contained inside this connector
/// </summary>
/// <param name="r">the RectangleF as a candidate, usually the mouse coordinates converted to a zero sized rectangle.</param>
/// <returns>True/false</returns>
public override bool Hit(RectangleF r)
{
if ((r.Width == 0) && (r.Height == 0))
return ConnectionGrip().Contains(r.Location);
return r.Contains(ConnectionGrip());
}
/**//// <summary>
/// Overrides the Paint of the control and paint a little connection point or a highlighted connecting widget to
/// show the user that a connection is possible.
/// </summary>
/// <remarks>
/// The parent\'s Hover boolean can be used to check if the mouse is currently hovering over this object. This enables a status message or a different shape.
/// </remarks>
/// <param name="g">The Graphics or canvas onto which to paint.</param>
public override void Paint(Graphics g)
{
Rectangle r = Rectangle.Round(ConnectionGrip());
Color Line = Color.White;
if (IsHovered) Line = Color.Black;
Color Fill = Color.FromArgb(49, 69, 107); // dark blue
if (IsHovered)
{
if ((mAllowMultipleConnections) || (mConnections.Count < 1))
Fill = Color.FromArgb(0, 192, 0); // medium green
else
Fill = Color.FromArgb(255, 0, 0); // red
}
g.FillRectangle(new SolidBrush(Fill), r);
g.DrawRectangle(new Pen(Line, 1), r);
/**//*This piece of code has been replaced by the tooltip
*
if (IsHovered)
{
Font f = new Font("Tahoma", 8.25f);
Size s = g.MeasureString(Text + " [" + this.Connections.Count + "]", f).ToSize();
Rectangle a = new Rectangle(r.X - (s.Width / 2), r.Y + s.Height + 6, s.Width, s.Height + 1);
Rectangle b = a;
a.Inflate(+3, +2);
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 255, 231)), a);
g.DrawRectangle(new Pen(Color.Black, 1), a);
g.DrawString(Text + " [" + this.Connections.Count + "]", f, new SolidBrush(Color.Black), b.Location);
}
*/
}
/**//// <summary>
/// Necessary implementation of the abstract delete method defined in Entity
/// </summary>
protected internal override void Delete()
{
}
/**//// <summary>
/// Update/refresh the connector\'s appearance
/// </summary>
public override void Invalidate()
{
if (mBelongsTo == null) return;
IGraphSite c = mBelongsTo.Site;//should return the underlying canvasobject
if (c == null) return;
RectangleF r = ConnectionGrip();//get the neighborhood of the connector
if (IsHovered) r.Inflate(+100, +100); // make sure a sufficient piece of the neighborhood will be refreshed.
c.Invalidate(Rectangle.Round(r)); //and refresh it by calling the control\'s invalidate method.
}
/**//// <summary>
/// Returns the cursor for the current connector
/// </summary>
/// <param name="p">The cursor location</param>
/// <returns>A grip cursor, looks like a focus/target</returns>
public override Cursor GetCursor(PointF p)
{
return MouseCursors.Grip;
}
/**//// <summary>
/// Represents the spot around a connector that lits up and where the connections is attaching itself
/// The color is determined by various things, can be red, grey or green. See the Hover conditions in the paint handler for this.
/// </summary>
/// <returns>A little rectangleF (3x3)</returns>
public RectangleF ConnectionGrip()
{
PointF p = mBelongsTo.ConnectionPoint(this);
RectangleF r = new RectangleF(p.X, p.Y, 0, 0);
r.Inflate(+3, +3);
return r;
}
#endregion
ISerializable Members#region ISerializable Members
/**//// <summary>
/// ISerializable implementation
/// </summary>
/// <param name="info">the serialization info</param>
/// <param name="context">the streaming context</param>
[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("mName", this.mName);
info.AddValue("mAllowMultipleConnections", this.mAllowMultipleConnections);
info.AddValue("mConnectorLocation", this.mConnectorLocation,typeof(ConnectorLocation));
info.AddValue("mConnectionShift", this.mConnectionShift, typeof(float));
info.AddValue("mAllowNewConnectionsFrom", this.mAllowNewConnectionsFrom);
info.AddValue("mAllowNewConnectionsTo", this.mAllowNewConnectionsTo);
}
#endregion
}
}
字段介绍:这里介绍有几个重要的字段:mBelongsTo 此字段作用是保存本点所属于那个shape,private mConnections 此字段作用是保存本点所连接的所以connection,mAllowNewConnectionsFrom 此字段作用是确定本点是否允许新的线画出, mAllowNewConnectionsTo 此字段作用是是否允许新的线连入本点。
方法暂不了解,有兴趣读者可以自己去看。