Creating a Simple Sheet Designer in C#

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Code: Geming.Sisc.msi

Contents

Contents of this article:

  • Contents
  • Introduction
  • Problem
  • Requirements
  • Solution
  • Snapshots
  • Component Design
  • Class Diagrams
  • Database Diagram
  • Characteristics
  • Background
  • Code Highlights
  • Download

Introduction

Today, we are going to create a simple application, actually a simple sheet designing tool. This tool gives the user the flexibility to design his sheets, reports, bills, invoices, and receipts (whatever.)

In this writing, we will refer to reports, bills, invoices, receipts, etc. with just the name sheets. For this, we will need to give a sheet a definition.

A sheet is just like an empty page (i.e. template) that contains sheet items. For example, a resume template is a sheet that has many items (name, birth date, address, etc.) A cash receipt is a sheet that has a few items (date, amount, charged to, received by, etc.)

We will go through this tool in a nice way. We will begin by a very simple system analysis and application design. After that, we will get into coding.

Actually, I€™m not an architect, and I think I will never be. So please, DO NOT blame me for this bad analysis. It is just an illustration to get you have a solid understanding of what our application is designed for.

Problem

The user is tied into the sheet designs that the developer has created for him. The user should have the ability to design his own sheets and/or to edit application defined sheets.

Requirements

User Requirements

The following is list of common user requirements:

  • The application should allow the user to create, edit, and delete sheets, and to group those sheets into categories he creates.
  • For the sake of simplicity, those categories would be only one level, no nested categories are allowed.
  • The application should be persistent. The data should be stored in a database and loaded when the user needs it.
  • The sheet should be loaded with right data and printed whenever the user asks.
  • Like Visual Studio, the user should have a Toolbox that has all types of sheet items. The user could insert a sheet item into his sheet by drawing it into the screen, dragging it from the toolbox, or just double-clicking its icon in the toolbox.
  • The user should have a ruler to allow him measuring sheet item dimensions. In addition, he should have a design-time-only grid.
  • The user should be allowed to set attributes of the sheet like the page setup, grid settings, background color, etc.
  • Not all sheet attributes are printed out; some are for design-mode only (like background color, and grid.)
  • Each type of sheet items should have its own attributes and the user should be allowed to change them too.
  • The user should be allowed to drag sheet items around the screen and position them.
  • The user should be allowed to cut, copy, paste, and delete sheet items.
  • Of course, the user should be allowed to print out the sheet, and to preview it too.
  • The application should be generic to be used in any system and in any application.
  • Other pieces of the system should have the possibility to interact with the sheet.

Functional Requirements

Common functional (developer) requirements are:

  • Abstraction. Component/Class abstraction should be considered into the design. The system should consist of several components each of which groups a related features together (e.g. interface objects, business objects, and data management.)
  • Extensibility. The system should be extensible. A good class hierarchy should be created, and derivation (inheritance) should be taken into consideration. In addition, every sheet item should be represented by a class in this hierarchy.
  • Technically, sheet items would be called shapes. Because they are just drawings into the sketch (or sheet.)
  • To allow the user to work with sheet items (shapes) and the application to populate the sheet with data, sheet items should not be drawn directly into the sheet page. Instead every item should represented by a class that has its own drawing routine.
  • The sheet should be a container for the shapes. All shapes are children of the sheet.
  • The sheet and rulers should be Windows controls to allow them to be hosted by a Windows Form.
  • Sheet items should be Windows controls too to allow them to be hosted by the sheet.
  • The sheet items should be owner-drawn controls and they should not be derived from existing Windows controls to help integrating them easily into the sheet.
  • For the sake of simplicity, the sheet and shapes should be serialized into XML and stored in the database.
  • The database should be a SQL Server database to allow faster communication and easier manipulation of XML data.
  • The database should have three tables for the three core system components, the category, the sheet, and the shape.
  • Every sheet item in a given sheet should have a unique name (or a tag) to allow other system components to interact with it (e.g. populate it with the right data.)
  • The developer should have the ability to control the quality of the painting process for each control or item independently.

Solution

After going through project requirements and considering a sophisticated system design, we got a nice plan for our project that would be called Geming SISC (Sheet Infrastructure Components.)

This project would be created using C# and .NET 2.0 (or future versions of course.)

Snapshots

The following are final snapshots of the application. Figure 1 shows a cash receipt sheet designed by labels, boxes, and lines. Figure 2 shows a simple resume template designed by only a few labels and a picture. The left pane of the application lists current sheets grouped by their categories.

Figure 01 - Geming SISC (Cash Receipt)
Figure 01 - Geming SISC (Cash Receipt)
Figure 2 - Geming SISC (Resume Template)
Figure 2 - Geming SISC (Resume Template)

As you know other system components could fill those fields up with correct information.

Component Design

Figure 3 shows the three components of our system.

Figure 3 - Geming SISC Component Design
Figure 3 - Geming SISC Component Design

The three core components of our system, Geming SISC are:

  • Geming.Sisc.Infrastructure:
    Contains the sheet control and shapes controls (label, text box, etc.) The sheet, rulers, and sheet items controls are all derived from System.Windows.Forms.Control.
  • Geming.Sisc.Data:
    Business objects that would be sent to the data among database manager objects. This component references the Geming.Sisc.Infrastructure component.
  • Geming.Sisc.Driver:
    The application interface that would be used to design sheets. It references the other two components.

Class Diagrams

Extensibility is one of the main goals of the system. A flexible class hierarchy should be considered as well as derivation (i.e. inheritance) of controls for other external objects.

The following is the class hierarchy for the sheet and the ruler controls.

Figure 4 - Sheet and Rulers Class Hierarchy
Figure 4 - Sheet and Rulers Class Hierarchy

As we can see, the base class is the System.Windows.Forms.Control class. This allows the sheet and rulers controls to be inserted into a Windows form or a Windows control.

The following figure, figure 5, shows the class hierarchy of sheet items (technically called shapes.)

Figure 5 - Sheet Items (Shapes) Class Hierarchy
Figure 5 - Sheet Items (Shapes) Class Hierarchy

As we can see, the base class for all shapes is the abstract Geming.Sisc.Infrastructure.ShapeBase class which inherits from System.Windows.Forms.Control class. All other shapes are derived from ShapeBase.

Two edit shapes were created, TextBoxShape that has a look like a Windows Text Box, and LabelShape that has a look like a normal Windows Label. Both are derived from the abstract EditableShapeBase.

Other shapes are BoxShape, LineShape, ImageShape, and CheckBoxShape.

All classes are serializable (implement System.Runtime.Serialization.ISerializable interface,) so they can easily converted into XML and pushed to the database.

For simplicity, we have developed just the box, line, image, check box, and two edit shapes (or sheet items.) You can go further and create any other shapes you like. In addition, you can create more specific items like CurrencyField, DateField, etc.

For more detailed class diagrams like those shows class members, check the application code.

Database Diagram

In its simplicity, database is defined as the following diagram illustrates:

Figure 6 - Geming SISC Database Diagram
Figure 6 - Geming SISC Database Diagram

Notice that, all data operations are carried out through stored procedures in the database.

The Shape.Value column is of the type xml to allow easier manipulation of XML data in the future.

Characteristics

Here are some of the characteristics (i.e. attributes) of the sheet (some are represented by properties):

  • Background color:
    The user should be able change the background color. Notice that the background color is not printed.
  • Non-printable grid:
    To help the user position sheet items. The user should be able to display them or not. In addition, the user can change the grid color.
  • Margin:
    The application should set the page margin based on print settings.
  • Title:
    Every sheet has a title, a description, and a category.

In addition, next is a list of some the characteristics of a shape (sheet item):

  • Selected:
    Is the shape currently selected or not. The user could select a shape by the mouse. A selection frame is drawn around the shape when selected.
  • Non-printable size grip:
    Each shape should have a size grip to allow the user to resize the shape.
  • Cloning:
    The shape should be able to be cloned; that is copied, to allow the copy and paste feature.

Background

Here are some refreshers of techniques we use in this system:

  • Painting

We will rely on custom painting in most situations. Therefore, well request help from System.Drawing classes specially the System.Drawing.Graphics class.

In some shapes like those mimic existing Windows controls (like the text box and the check box,) we will get help from classes in System.Windows.Forms.VisualStyles namespace to reflect the visual styles of Windows in our controls. In addition, System.Windows.Forms.ControlPaint class is used for drawing borders and selection rectangles.

  • Painting Quality

Every control in our project (sheet, rulers, and shapes) has a paining quality property that determines the quality of the drawing (low, medium, and high.) For this to work we will make use of some properties of the System.Drawing.Graphics object like those related to smoothing and anti-aliasing feature.

  • Serialization

All serialized objects should be marked with System.SerializableAttribute attribute. With help from System.Runtime.Serialization namespace we could customize the serialization process.

The core interface that would allow us to customize the serialization process is the System.Runtime.Serialization.ISerializable interface (implemented in all serializable classes.) Notice that, we should add the deserialization constructor to get correct deserialization.

  • Database

The database is a SQL Server client database with all operations included as stored procedures.

The system uses two-tier architecture; means that it accesses the database directly using just three objects, a connection, a command, and a data reader.

  • Design-Mode Support

For extending design-mode support we have created custom designer service for the Sheet class that inherits the System.Windows.Forms.Design.ParentControlDesigner class to allow nested controls in the Sheet object in the design-mode.

Code Highlights

In this section we will talk about significant blocks of code that would be of interest.

  • Painting Routines

The following is the code for OnPaint() routine overridden by only the ShapeBase class.

Listing 1 – ShapeBase.OnPaint() Method Code Listing
protected override void OnPaint(PaintEventArgs e)
{
    GraphicsManager.SetQuality(e.Graphics, PaintingQuality);

    ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle, this.ForeColor, ButtonBorderStyle.Dotted);

    PaintShape(e.Graphics);

    if (Selected)
        DrawSelectionFrame(e.Graphics);

    ControlPaint.DrawSizeGrip(e.Graphics, this.BackColor, GetResizeGripRect());
}

This function first calls the GraphicsManager.SetQuality() function that sets the quality attributes of the Graphics object. We will get back to this function in about a moment.

After that the function paints the control border using the System.Windows.Forms.ControlPaint class.

Next comes the interesting point. The function calls the virtual function PaintShape() that a derived class overrides to provide its own drawing routines.

For example, the TextBoxShape class has this PaintShape() override:

Listing 2 – TextBoxShape.PaintShape() Method Code Listing
public override void PaintShape(Graphics dc)
{
    base.PaintShape(dc);

    using (Brush b = new SolidBrush(this.BackColor))
    dc.FillRectangle(b, this.ClientRectangle);

    using (Pen p = new Pen(SystemColors.ActiveCaption, 1))
    {
        p.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
        Rectangle r = this.ClientRectangle;
        dc.DrawRectangle(p, r);
    }

    Rectangle rect = this.ClientRectangle;
    rect.Offset(2, 2);
    rect.Width -= 4; rect.Height -= 4;

    StringFormat format = new StringFormat();
    format.LineAlignment = this.Alignment;
    if (this.RightToLeft == RightToLeft.Yes)
        format.FormatFlags = StringFormatFlags.DirectionRightToLeft;

    using (Brush b = new SolidBrush(this.ForeColor))
        dc.DrawString(this.Text, this.Font, b, rect, format);
}

After that the OnPaint() function draws selection frame if the shape is currently selected.

Just before the function closes, it calls the ControlPaint.DrawSizeGrip() function to draw the sizing grip that the user would resize the shape from.

  • Painting Quality

In our library Geming.Sisc.Infrastructure, we have created a helper class, GraphicsManager, which contains only one function, SetQuality().

This function accepts two input parameters, the graphics object and the quality you wish to set to that object. The following is the code for the SetQuality() function.

Listing 3 – GraphicsManager.SetQuality() Method Code Listing
public static void SetQuality(System.Drawing.Graphics g, PaintingQuality quality)
{
    if (g == null)
        throw new ArgumentNullException("g");

    if (quality == PaintingQuality.High)
    {
        g.CompositingQuality = CompositingQuality.AssumeLinear;
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.PixelOffsetMode = PixelOffsetMode.Half;
        g.SmoothingMode = SmoothingMode.AntiAlias;
        g.TextRenderingHint =
        System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
    }
    else if (quality == PaintingQuality.Medium)
    {
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.InterpolationMode = InterpolationMode.Bilinear;
        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
        g.SmoothingMode = SmoothingMode.HighQuality;
        g.TextRenderingHint =
        System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
    }
    else
    {
        g.CompositingQuality = CompositingQuality.Default;
        g.InterpolationMode = InterpolationMode.Default;
        g.PixelOffsetMode = PixelOffsetMode.Default;
        g.SmoothingMode = SmoothingMode.Default;
        g.TextRenderingHint =
        System.Drawing.Text.TextRenderingHint.SystemDefault;
    }
}

Download

The application Geming.Sisc along with its code is available for download here.

Download Geming.Sisc

Introducing RSS; Developing a Simple RSS Reader

هذه المقالة متوفرة أيضا باللغة العربية، اقرأها هنا.

Code: Geming.WinForms.RssBars.zip

Contents

Contents of this writing:

  • Contents
  • Overview
  • Definition
  • Feeds
  • Aggregators/Readers
  • Version History
  • Schema
  • Sample; RSS Bars Library
  • Download
  • Further Readings

Overview

This writing does not include a full discussion or even the full details of RSS or XML. Rather, it includes a nice introduction to RSS and its XML schema. In addition, it incorporates what you get in a sample application that is easy-to-code, understand, and to extend.

Definition

RSS (commonly expanded as Really Simple Syndication or, sometimes, Rich Site Summary) is a XML content with specific schema used to deliver frequently changing web content (like news headlines, blogs, etc.).

RSS content is also known as a feed, web feed, syndication feed, web syndication, and a channel. It is widely known and distinguished by its icon €œ€.

RSS feeds are usually files that reside in a specific location. Those files usually (not extensively) has the extension rss or xml.

Feeds

Today, most -if not all – of the blogs and sites that have frequently changing web content incorporate RSS.

For instance, The New York Times has more than one hundred of RSS feeds available for subscription (listed here.) Every feed delivers the latest headlines for a specific category (Technology, Sports, etc.)

Aggregators/Readers

How can you benefits from RSS feeds? Surely, XML data is not the flexible and readable content that can be used. Thus, users usually access feeds via applications (or web clients) that are known as Feed Readers, RSS Readers, and Aggregators. Those applications read the RSS XML content, parse it, and display feed items (e.g. news headlines) to the user in a friendly interface.

Version History

RSS undergoes several changes that result in different versions and two major branches:

  1. RDF (Resource Description Framework) or RSS 1.* in other words.
  2. RSS 2.*

We will assume RSS 2.* is our discussion.

Schema

As any other XML format, RSS has a specific schema that RSS contents (i.e. feeds) should comply with; they required to implement obligatory elements, and they had the choice to implement other optional elements.

As a matter of discussion, we will take the CodeProject latest articles RSS feed (available here) as an example and extract the RSS schema from it.

The following is a sample from the CodeProject RSS feed content (at the time of this writing):


    
        The Code Project Latest Articles
        http://www.codeproject.com
        Latest Articles from The Code Project
        en-us
        
            The Code Project
            
            http://www.codeproject.com
            100
            30
            The Code Project
        
        Copyright © CodeProject, 1999-2010
        webmaster@codeproject.com
        Sun, 04 Apr 2010 12:27:00 GMT
        20
        C# Hand-coded goodness
        
            Comparison of Architecture presentation patterns MVP(SC),MVP(PV), ...
            This article will compare four important architecture ...
            http://www.codeproject.com/KB/aspnet/ArchitectureComparison.aspx
            Shivprasad koirala
            Sun, 04 Apr 2010 12:27:00 GMT
            ASP.NET
            http://www.codeproject.com/KB/aspnet/ArchitectureComparison.aspx
        
        
            Arcade Button in Expression Blend & Silverlight
            Discover the power of the Grid object, & how it controls ...
            http://www.codeproject.com/KB/expression/ArcadeButton.aspx
            Alan Beasley
            Sun, 04 Apr 2010 11:42:00 GMT
            Expression
            http://www.codeproject.com/KB/expression/ArcadeButton.aspx
        
        
            How to translate your forms application
            Translate your forms application to multiple languages ...
            http://www.codeproject.com/KB/dotnet/forms-translator.aspx
            Davide Vitelaru
            Sun, 04 Apr 2010 07:19:00 GMT
            .NET Framework
            http://www.codeproject.com/KB/dotnet/forms-translator.aspx
        
    

If we have a look at the file in XML Notepad we can see the following results:

To gain more understanding of the schema, let’s have a look at this diagram:

Required elements surrounded by the red border. Many other optional elements are available.

Most elements are self-explanatory from their names. However, the following maybe need more explanation:

  • rsschannellanguage:
    Content language (e.g. en-us for English for United States.)
  • rsschannellastBuildDate:
    The date of the last change of the content.
  • rsschannelttl:
    Time to Live. The number of minutes that indicate how long a channel can be cached before refreshing from the source. You would ignore this element, in many cases.
  • rsschannelgenerator:
    The name of the program used to generate this feed.
  • rsschannelitemguid:
    A Globally Unique Identifier used to identify this feed item.

Sample; RSS Bars Library

Our sample project is not an application in itself. Actually it is a WinForms control library that is called Geming.WinForms.RssBars. This library includes bars that read RSS content from a specific feeds and display it to the user.

This is an extensible library you can extend it to read from any RSS feed you like. The following are snapshots of the RssBars controls (reading CodeProject, Just Like a Magic, BBC, and the Nile News channels.)




The following figure shows library class diagram:

As you see, we have only one business object, RssItem structure. It encapsulates fields related to a feed item.

The RssBar is the base MustInherit (abstract in C#) class. It defines the base functionality of a RSS bar. All other classes are just children of the base class. They incorporate the functionality of RssBar by just setting its RSS feed path.

The RssBar requires two parameters for instantiation, the RSS path, and the banner image. For the sake of performance, we have required the developer to pass a banner image of the feed instead of automatically loading it from the image element of the feed content.

To avoid duplication, members of the RssBar are documented in the code.

The core function of the RssBar is the ReadRss() function. This function accesses the RSS feed and populates the list of feed items and display them to the user.

Since RSS is a XML format, we will need to reference the System.Xml.dll library as it is the core library for accessing XML via .NET. (Do not forget to import the System.Xml namespace.)

The following is a sample from the function code. Code abbreviated for clarity.

Public Sub ReadRss()
    ' Checking design mode, exit if True

    ' Preparing the screen

    ' The XML Document
    Dim xmlDoc As New Xml.XmlDocument
    ' Loading the RSS feed, should fail if network is not available
    xmlDoc.Load(m_rss)

    ' Accessing the €œchannel€ element
    Dim ndChannel As Xml.XmlNode = xmlDoc.Item("rss").Item("channel")

    ' Comparing publication date to one we have
    ' continue if something new

    ' Item cocollection
    Dim collItems As New Collections.Generic.List(Of RssItem)
    Dim ndItem As Xml.XmlNode

    ' Enumerating through the items
    ' and populating the collection
    For i As Integer = 0 To ndChannel.ChildNodes.Count - 1
        ndItem = ndChannel.ChildNodes(i)
        If (ndItem.Name = "item") Then
            collItems.Add( _
            NewRssItem(ndItem.Item("title").ChildNodes(0).InnerText, _
            ndItem.Item("link").ChildNodes(0).InnerText, _
            ndItem.Item("description").ChildNodes(0).InnerText))
        End If
    Next

    ' Checking if items cound

    ' Clear existing items

    Do While enumerator.MoveNext

        ' Item

        lbl = New Label
        ' Creating a Label for the item
        ' and filling its fields
        Me.CtrlsPanel.Controls.Add(lbl)

        ' Adding handlers, so we could fire events
        AddHandler lbl.Click, AddressOf Me.RssItem_Click
        AddHandler lbl.MouseMove, AddressOf Me.RssItem_MouseMove

        ' Image
        image = New PictureBox
        ' Adding the banner image between items
        Me.CtrlsPanel.Controls.Add(image)

        ' Adding event handlers, so we could fire events
        AddHandler image.Click, AddressOf Image_Click
        AddHandler image.MouseMove, AddressOf Image_MouseMove
    Loop

    ' Finalization
End Sub

Child classes simply do not contain any code, just the line that instantiates the base RssBar and sets the RSS feed path and image. For instance,

    Public Sub New()
MyBase.New("http://www.codeproject.com/webservices/articlerss.aspx?cat=1", m_image)
Me.RightToLeft = Windows.Forms.RightToLeft.No
End Sub

Download

Download Geming.WinForms.RssBars Sample Code

Further Readings

Need more about RSS? Here are a few good references: