One of the inherent capabilities of all shape classes is the ability to have other shape objects embedded in them. This is a great way of making compound shapes. This topic explains how to create a custom compound shape that combines several built-in shapes and serves as a watermark.
To create this custom compound shape, define a custom shape class, called CompanyWatermark, and set the properties to customize this appearance. This custom shape combines several elements: a background gradient fades from a specified color to transparency; an embedded shape contains an image of the company logo; a separate embedded text shape spells the company name; and a text shape provides additional information such as Web site address or company motto or security classification.
Start by deriving a class from the standard RectangleShape class. This creates a rectangular palette in which to place the embedded shapes. You could just as easily use other shapes such as ellipses, or polygons, but your embedded shapes may be "clipped" (because embedded shapes do not exceed the boundaries of the parent shape).
Then create properties for accessing the internal shapes. One of the benefits of creating a compound shape is that you can hide many of the unnecessary properties of the embedded shapes. You can expose, through custom properties, only the pertinent information. The first property is the "CompanyColor" property. This is the main color in the background gradient, which gradually fades to transparency in the main shape. It is also alpha-blended so as not to fully obscure the sheet below. With the gradient class, other properties such as Style, which determines the gradient direction and type of gradient, can also be set. This example uses a Style of GradientStyle.TopDown.
The next property is an image property called "CompanyLogo". This property sets the graphic to be displayed in the embedded logo shape. This example locks the logo shape to the upper left corner of the watermark. You could very simply extend this with properties to allow alignment of the logo.
The most important part of the watermark is the company name. You can create this with an embedded TextShape object to represent the company name. This has been exposed on the watermark shape as the "CompanyName" property, which is a string. There are many customizable features of the TextShape class that can be exposed such as Font or ForeColor, though they are not exposed here. Also, for simplicity of this sample, the company name shape is locked to be centered in the watermark shape.
And, finally, there is a secondary TextShape object that holds some additional text information in the watermark. This could be a company motto, slogan, Web site address or even words like "CONFIDENTIAL" or "Copyright 2005". Anchor this text to the bottom left corner of the watermark shape for this example. Many additional properties can be set on this embedded shape. This example only exposes items of interest. The text for this shape is exposed as the "CompanyText" property.
The following code adds the compound shape:
C# |
Copy Code
|
---|---|
private void Form1_Load(object sender, EventArgs e) { CompanyWatermark test = new CompanyWatermark(0, 0, 550, 200); fpSpread1_Sheet1.AddShape(test); } |
Visual Basic |
Copy Code
|
---|---|
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim test As New CompanyWatermark(0, 0, 550, 200) FpSpread1_Sheet1.AddShape(test) End Sub |
The following code is from the WatermarkShape.cs file and creates the compound shape.
C# |
Copy Code
|
---|---|
using System; using System.Drawing; using System.Runtime.Serialization; using FarPoint.Win; using FarPoint.Win.Spread.DrawingSpace; using System.Xml; public class CompanyWatermark : RectangleShape, ISerializable { private Color mCompanyColor = Color.Green; private Image mCompanyLogo = WatermarkShape.Properties.Resources.SampleLogo; private string mCompanyName = "[Company Name]"; private string mCompanyText = "[Company Text]"; internal CompanyWatermark() { } // required for ISerializeSupport public CompanyWatermark(int left, int top, int width, int height) : base() { CanRotate = false; SetBounds(left, top, width, height); UpdateChildren(); } public CompanyWatermark(SerializationInfo info, StreamingContext context) : base(info, context) { mCompanyColor = (Color)info.GetValue("cc", typeof(Color)); mCompanyLogo = (Image)info.GetValue("cl", typeof(Image)); mCompanyName = info.GetString("cn"); mCompanyText = info.GetString("ct"); UpdateChildren(); } public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("cc", mCompanyColor); info.AddValue("cl", mCompanyLogo); info.AddValue("cn", mCompanyName); info.AddValue("ct", mCompanyText); } public Color CompanyColor { get { return mCompanyColor; } set { mCompanyColor = value; UpdateChildren(); } } public Image CompanyLogo { get { return mCompanyLogo; } set { mCompanyLogo = value; UpdateChildren(); } } public string CompanyName { get { return mCompanyName; } set { mCompanyName = value; UpdateChildren(); } } public string CompanyText { get { return mCompanyText; } set { mCompanyText = value; UpdateChildren(); } } public override void Rotate(float angle) { base.Rotate(angle); foreach (PSShape shape in ContainedObjects) shape.RotationAngle = angle; } public override bool Deserialize(XmlNodeReader r) { bool inCompanyColor = false; bool inCompanyLogo = false; XmlDocument doc = new XmlDocument(); XmlNode node; XmlNodeReader r2; XmlNodeReader r3; XmlNodeReader r4; r.MoveToElement(); node = doc.ReadNode(r); r2 = new XmlNodeReader(node); r3 = new XmlNodeReader(node); r4 = new XmlNodeReader(node); PSObject.Deserialize(this, r2); PSShape.Deserialize(this, r3); while (r4.Read()) { switch (r.NodeType) { case XmlNodeType.Element: if (r.Name.Equals("CompanyColor")) inCompanyColor = true; else if (r.Name.Equals("CompanyLogo")) inCompanyLogo = true; else if (r.Name.Equals("CompanyName")) mCompanyName = Serializer.DeserializeString(r); else if (r.Name.Equals("CompanyText")) mCompanyText = Serializer.DeserializeString(r); break; case XmlNodeType.Text: if (inCompanyColor) mCompanyColor = Serializer.DeserializeColorValue(r.Value); else if (inCompanyLogo) mCompanyLogo = Serializer.DeserializeImage(r.Value); break; case XmlNodeType.EndElement: if (inCompanyColor && r.Name.Equals("CompanyColor")) inCompanyColor = false; else if (inCompanyLogo && r.Name.Equals("CompanyLogo")) inCompanyLogo = false; break; } } return true; } public override bool Serialize(XmlTextWriter w) { w.WriteStartElement("PSShape"); w.WriteAttributeString("class", this.GetType().FullName); w.WriteAttributeString("assembly", this.GetType().Assembly.FullName); PSShape.Serialize(this, w); Serializer.SerializeColor(mCompanyColor, "CompanyColor", w); Serializer.SerializeImage(mCompanyLogo, "CompanyLogo", w); Serializer.SerializeString(mCompanyName, "CompanyName", w); Serializer.SerializeString(mCompanyText, "CompanyText", w); w.WriteEndElement(); // object return true; } private void UpdateChildren() { ShapeOutlineThickness = 0; if( ContainedObjects.Count == 0 ) { // create the child shapes // gradient effect for company color BackColor = Color.Transparent; Gradient.Sections = new GradientSection[] { new GradientSection(mCompanyColor, 255, 200), new GradientSection(Color.White, 255, 255) }; Gradient.Style = GradientStyle.LinearTopDown; // company logo is aligned to left and uses image width and height to align company text below RectangleShape logo = new RectangleShape(); logo.BackColor = Color.Transparent; logo.ShapeOutlineThickness = 0; logo.SetBounds(0, 0, mCompanyLogo.Width, mCompanyLogo.Height); logo.Picture = mCompanyLogo; logo.PictureTransparencyColor = Color.White; ContainedObjects.Add(logo); TextShape name = new TextShape(); name.Text = mCompanyName; name.ForeColor = Color.Orange; name.ShapeOutlineColor = Color.Black; name.ShapeOutlineStyle = System.Drawing.Drawing2D.DashStyle.Solid; name.ShapeOutlineThickness = 1; ContainedObjects.Add(name); name.SetBounds(logo.Width + 5, (logo.Height - name.Height) / 2, name.Width, name.Height); TextShape text = new TextShape(); text.Text = mCompanyText; text.ForeColor = Color.Red; text.ShapeOutlineColor = Color.Black; text.ShapeOutlineStyle = System.Drawing.Drawing2D.DashStyle.Solid; text.ShapeOutlineThickness = 1; ContainedObjects.Add(text); text.SetBounds(0, logo.Height + 5, text.Width, text.Height); } else { // update the child shapes RectangleShape logo = (RectangleShape)ContainedObjects[0]; TextShape name = (TextShape)ContainedObjects[1]; TextShape text = (TextShape)ContainedObjects[2]; Gradient.Sections = new GradientSection[] { new GradientSection(mCompanyColor, 50), new GradientSection(Color.White, 50) }; logo.Picture = mCompanyLogo; name.Text = mCompanyName; text.Text = mCompanyText; } } } |
Visual Basic |
Copy Code
|
---|---|
Imports System.Runtime.Serialization Imports System.Xml Imports FarPoint.Win Imports FarPoint.Win.Spread.DrawingSpace <Serializable()> Public Class CompanyWatermark Inherits RectangleShape Implements ISerializable Private mCompanyColor As Color = Color.Green Private mCompanyLogo As Image = My.Resources.SampleLogo Private mCompanyName As String = "[Company Name]" Private mCompanyText As String = "[Company Text]" Friend Sub New() End Sub ' required for ISerializeSupport Public Sub New(left As Integer, top As Integer, width As Integer, height As Integer) MyBase.New() CanRotate = False SetBounds(left, top, width, height) UpdateChildren() End Sub Public Sub New(info As SerializationInfo, context As StreamingContext) MyBase.New(info, context) mCompanyColor = DirectCast(info.GetValue("cc", GetType(Color)), Color) mCompanyLogo = DirectCast(info.GetValue("cl", GetType(Image)), Image) mCompanyName = info.GetString("cn") mCompanyText = info.GetString("ct") UpdateChildren() End Sub Public Overrides Sub GetObjectData(info As SerializationInfo, context As StreamingContext) MyBase.GetObjectData(info, context) info.AddValue("cc", mCompanyColor) info.AddValue("cl", mCompanyLogo) info.AddValue("cn", mCompanyName) info.AddValue("ct", mCompanyText) End Sub Public Property CompanyColor() As Color Get Return mCompanyColor End Get Set mCompanyColor = Value UpdateChildren() End Set End Property Public Property CompanyLogo() As Image Get Return mCompanyLogo End Get Set mCompanyLogo = Value UpdateChildren() End Set End Property Public Property CompanyName() As String Get Return mCompanyName End Get Set mCompanyName = Value UpdateChildren() End Set End Property Public Property CompanyText() As String Get Return mCompanyText End Get Set mCompanyText = Value UpdateChildren() End Set End Property Public Overrides Sub Rotate(angle As Single) MyBase.Rotate(angle) For Each shape As PSShape In ContainedObjects shape.RotationAngle = angle Next End Sub Public Overrides Function Deserialize(r As XmlNodeReader) As Boolean Dim inCompanyColor As Boolean = False Dim inCompanyLogo As Boolean = False Dim doc As New XmlDocument() Dim node As XmlNode Dim r2 As XmlNodeReader Dim r3 As XmlNodeReader Dim r4 As XmlNodeReader r.MoveToElement() node = doc.ReadNode(r) r2 = New XmlNodeReader(node) r3 = New XmlNodeReader(node) r4 = New XmlNodeReader(node) PSObject.Deserialize(Me, r2) PSShape.Deserialize(Me, r3) While r4.Read() Select Case r.NodeType Case XmlNodeType.Element If r.Name.Equals("CompanyColor") Then inCompanyColor = True ElseIf r.Name.Equals("CompanyLogo") Then inCompanyLogo = True ElseIf r.Name.Equals("CompanyName") Then mCompanyName = Serializer.DeserializeString(r) ElseIf r.Name.Equals("CompanyText") Then mCompanyText = Serializer.DeserializeString(r) End If Exit Select Case XmlNodeType.Text If inCompanyColor Then mCompanyColor = Serializer.DeserializeColorValue(r.Value) ElseIf inCompanyLogo Then mCompanyLogo = Serializer.DeserializeImage(r.Value) End If Exit Select Case XmlNodeType.EndElement If inCompanyColor AndAlso r.Name.Equals("CompanyColor") Then inCompanyColor = False ElseIf inCompanyLogo AndAlso r.Name.Equals("CompanyLogo") Then inCompanyLogo = False End If Exit Select End Select End While Return True End Function Public Overrides Function Serialize(w As XmlTextWriter) As Boolean w.WriteStartElement("PSShape") w.WriteAttributeString("class", Me.[GetType]().FullName) w.WriteAttributeString("assembly", Me.[GetType]().Assembly.FullName) PSShape.Serialize(Me, w) Serializer.SerializeColor(mCompanyColor, "CompanyColor", w) Serializer.SerializeImage(mCompanyLogo, "CompanyLogo", w) Serializer.SerializeString(mCompanyName, "CompanyName", w) Serializer.SerializeString(mCompanyText, "CompanyText", w) w.WriteEndElement() ' object Return True End Function Private Sub UpdateChildren() ShapeOutlineThickness = 0 If ContainedObjects.Count = 0 Then ' create the child shapes ' gradient effect for company color BackColor = Color.Transparent Gradient.Sections = New GradientSection() {New GradientSection(mCompanyColor, 255, 200), New GradientSection(Color.White, 255, 255)} Gradient.Style = GradientStyle.LinearTopDown ' company logo is aligned to left and uses image width and height to align company text below Dim logo As New RectangleShape() logo.BackColor = Color.Transparent logo.ShapeOutlineThickness = 0 logo.SetBounds(0, 0, mCompanyLogo.Width, mCompanyLogo.Height) logo.Picture = mCompanyLogo logo.PictureTransparencyColor = Color.White ContainedObjects.Add(logo) Dim name As New TextShape() name.Text = mCompanyName name.ForeColor = Color.Orange name.ShapeOutlineColor = Color.Black name.ShapeOutlineStyle = System.Drawing.Drawing2D.DashStyle.Solid name.ShapeOutlineThickness = 1 ContainedObjects.Add(name) name.SetBounds(logo.Width + 5, (logo.Height - name.Height) / 2, name.Width, name.Height) Dim text As New TextShape() text.Text = mCompanyText text.ForeColor = Color.Red text.ShapeOutlineColor = Color.Black text.ShapeOutlineStyle = System.Drawing.Drawing2D.DashStyle.Solid text.ShapeOutlineThickness = 1 ContainedObjects.Add(text) text.SetBounds(0, logo.Height + 5, text.Width, text.Height) Else ' update the child shapes Dim logo As RectangleShape = DirectCast(ContainedObjects(0), RectangleShape) Dim name As TextShape = DirectCast(ContainedObjects(1), TextShape) Dim text As TextShape = DirectCast(ContainedObjects(2), TextShape) Gradient.Sections = New GradientSection() {New GradientSection(mCompanyColor, 50), New GradientSection(Color.White, 50)} logo.Picture = mCompanyLogo name.Text = mCompanyName text.Text = mCompanyText End If End Sub End Class |