Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C#

MDI Application Case Study - Part I - Introduction

Rate me:
Please Sign up or sign in to vote.
4.91/5 (10 votes)
20 Nov 2015CPOL6 min read 21.5K   613   32   5
MDI Application Case Study - Part 1 - Introduction

Introduction

This is Part I of an ongoing case study for the development of an MDI application. The goal is to touch on many aspects of the process, in parts, to be a guide for handling different aspects of the general needs of such applications. The example program will be a inventory purchasing environment, and will be an MDI application for producing purchase orders, including the use of object data sources. This guide will assume you have a working knowledge of object oriented coding in general, as well as C# syntax. As we progress, we will cover most if not all of the familiar Multiple Document Interface type functions, and how to employ them in your application. Other notes of interest will be custom events, Win32 dllimports, Object Data Sources, XML and Binary serialization, Emailing, GDI Printing, and PDF incorporation using MigraDoc and PDFSharp libraries, and tool bar docking.

Our First Object Class - Item

Our first object class, Item, will contain information about each individual item in our sample company's inventory. Below is the start of our class, but as this case study progresses, we will be expanding this class to feature more properties, methods, and events. We will use a few conventions throughout this study. First, all private properties will be defined with names starting with the underscore character, to help differentiate scope as we start to incorporate more advanced code. Secondly, although you can easily just empty public properties with empty getters and setters, this habit for our case study will prove to be problematic as we progress, as there will be times when getting or setting, we will want to also run other lines of code. An empty getter or setter will not allow this, so we want to use private properties exposed by public definitions so that we can better control what happens on each get and set call.

C#
using System;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class Item
    {
        private String _productNumber;
        private String _description;
        private double _cost;
        private int _purchaseQty;

        public Item()
        {
            _productNumber = String.Empty;
            _description = String.Empty;
            _cost = 0;
            _purchaseQty = 0;
        }

        public String ProductNumber
        {
            get { return _productNumber; }
            set { _productNumber = value; }
        }

        public String Description
        {
            get { return _description; }
            set { _description = value; }
        }

        public double Cost
        {
            get { return _cost; }
            set { _cost = value; }
        }

        public int PurchaseQuantity
        {
            get { return _purchaseQty; }
            set { _purchaseQty = value; }
        }
    }
}

As you can see, so far this is pretty basic, a part number, description, cost, and quantity we are buying. Now let's touch on object inheritance as we create a collection class to handle groups of our Item objects. We create a collection class that inherits a typed list, List<T>. If you are unfamiliar with typed classes, they are somewhat advantageous. They will by default pass the objects it holds as the correct type, and will reject attempts to add objects of the incorrect type. Typed lists, List<T> can be found in the System.Collections.Generic library.

C#
using System;
using System.Collections.Generic;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class ItemCollection : List<Item>
    {
        public ItemCollection() { }
    }
}

The collection above is already extremely robust and ready to go, by inheriting the List<T> class, we already have an Add(Item), Remove(Item), and Contains(Item) methods, as well as this[int] getter/setter which will return the Item at the specified index. However, let's add a couple more interesting methods. In our case study, the item's product number will be a unique identifier, no two items will ever have the same product number. These 2 methods will help to facilitate this functionality for us. When you have multiple methods by the same name, but with different arguments, that's known as overloading a method.

C#
public bool Contains(String productNumber)
{
    foreach (Item i in this)
    {
        if (i.ProductNumber == productNumber) return true;
    }
    return false;
}

public Item this[String productNumber]
{
    get
    {
        foreach (Item i in this)
        {
            if (i.ProductNumber == productNumber) return i;
        }
        return null;
    }
}

As we add items into this collection, we can first call Contains(String) to be sure the item isn't already in the collection, or more accurately, to be sure another item with the same product number isn't already there. Then we can get the requested item using the this[String] getter. You could also put a set clause into the custom this[String] method if you wish, but we won't need it for this case study. The foreach clause is very nice, the only caveat with it is that the collection you are stepping through cannot be modified while the foreach clause is in effect. If you need to modify as you step through, then you'll need to use the for(;;) clause.

Object Inheritance - A Further Look

Next, let's create a few object classes we will need to handle addresses used throughout our application. We will create a base Address class, as well as 3 extended classes, ShippingAddress, VendorAddress, and BillingAddress. Fist, each of our three addresses we will use will all share a large number of properties, so let's create a base Address class that will include these shared properties.

C#
using System;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class Address
    {
        private String _attention;
        private String _companyName;
        private String _addressLine1;
        private String _addressLine2;
        private String _city;
        private String _state;
        private String _zipCode;

        public Address()
        {
            _attention = _companyName = _addressLine1 = _addressLine2 = 
            	_city = _state = _zipCode = String.Empty;
        }

        public String Attention
        {
            get { return _attention; }
            set { _attention = value; }
        }

        public String CompanyName
        {
            get { return _companyName; }
            set { _companyName = value; }
        }

        public String AddressLine1
        {
            get { return _addressLine1; }
            set { _addressLine1 = value; }
        }

        public String AddressLine2
        {
            get { return _addressLine2; }
            set { _addressLine2 = value; }
        }

        public String City
        {
            get { return _city; }
            set { _city = value; }
        }

        public String State
        {
            get { return _state; }
            set { _state = value; }
        }

        public String ZipCode
        {
            get { return _zipCode; }
            set { _zipCode = value; }
        }
    }
}

Who wants to write all that code 3 times? Again object orientation and inheritance helps us greatly. Now we can extend this base class in each of our extension address classes. First our BillingAddress:

C#
using System;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class BillingAddress : Address
    {
        private String _phoneNumber;
        private String _faxNumber;

        public BillingAddress()
        {
            _phoneNumber = _faxNumber = String.Empty;
        }
    }


    public String PhoneNumber
    {
        get { return _phoneNumber; }
        set { _phoneNumber = value; }
    }

    public String FaxNumber
    {
        get { return _faxNumber; }
        set { _faxNumber = value; }
    }
}

Again, due to inheritance, we automatically get all the properties contained in Address, so we just have to add the properties that make BillingAddress unique, PhoneNumber and FaxNumber. Next the VendorAddress:

C#
using System;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class VendorAddress : Address
    {
        private String _phoneNumber;
        private String _faxNumber;

        public VendorAddress()
        {
            _phoneNumber = _faxNumber = String.Empty;
        }

        public String PhoneNumber
        {
            get { return _phoneNumber; }
            set { _phoneNumber = value; }
        }

        public String FaxNumber
        {
            get { return _faxNumber; }
            set { _faxNumber = value; }
        }
    }
}

And finally, the ShippingAddress:

C#
using System;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class ShippingAddress : Address
    {
        private String _reference;

        public ShippingAddress()
        {
            _reference = String.Empty;
        }

        public String Reference
        {
            get { return _reference; }
            set { _reference = value; }
        }
    }
}

As you can see, inheritance saves us time, but it also provides a sense of hierarchy and organization. Our next class is the Vendor class. The vendor object class will hold all of the information for each source of products our sample company uses.

C#
using System;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class Vendor
    {
        private String _vendorID;
        private VendorAddress _address;

        public Vendor()
        {
            _vendorID = String.Empty;
            _address = new VendorAddress();
        }

        public String VendorID
        {
            get { return _vendorID; }
            set { _vendorID = value; }
        }

        public VendorAddress Address
        {
            get { return _address; }
            set { _address = value; }
        }
    }
}

And again, we want a collection to keep up with all of the vendors for our company, so we will create an extended List<T> VendorCollection. And the VendorID will be the unique identifier for vendors, so we will also overload the Contains and this methods to use the VendorID, similar to what we did in the ItemCollection above. 

C#
using System;
using System.Collections.Generic;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class VendorCollection : List<Vendor>
    {
        public VendorCollection() { }

        public bool Contains(String vendorID)
        {
            foreach (Vendor v in this)
            {
                if (v.VendorID == vendorID) return true;
            }
            return false;
        }

        public Vendor this[String vendorID]
        {
            get
            {
                foreach (Vendor v in this)
                {
                    if (v.VendorID == vendorID) return v;
                }
                return null;
            }
        }
    }
}

The final class for this section, and the last of our main object classes is the PurchaseOrder. This will keep up with all of the information about each specific order created, the addresses, the items purchased, the vendor, and all other pertinent information.

C#
using System;

namespace MDICaseStudyPurchasing.ObjectBase
{
    public class PurchaseOrder
    {
        private String _purchaseOrderNumber;
        private Vendor _vendor;
        private BillingAddress _billingAddress;
        private ShippingAddress _shippingAddress;
        private VendorAddress _vendorAddress;
        private ItemCollection _items;

        public PurchaseOrder()
        {
            _purchaseOrderNumber = String.Empty;
            _vendor = new Vendor();
            _billingAddress = new BillingAddress();
            _shippingAddress = new ShippingAddress();
            _vendorAddress = _vendor.Address;
            _items = new ItemCollection();
        }

        public String PurchaseOrderNumber
        {
            get { return _purchaseOrderNumber; }
            set { _purchaseOrderNumber = value; }
        }

        public Vendor Vendor
        {
            get { return _vendor; }
            set { _vendor = value; }
        }

        public BillingAddress BillingAddress
        {
            get { return _billingAddress; }
            set { _billingAddress = value; }
        }

        public ShippingAddress ShippingAddress
        {
            get { return _shippingAddress; }
            set { _shippingAddress = value; }
        }

        public VendorAddress VendorAddress
        {
            get { return _vendorAddress; }
            set { _vendorAddress = value; }
        }
    }
}

Just a note concerning handling of document data. It's tempting to try and consolidate data storage but referencing, but this is froth with potential mistakes. For example, you can see in our PurchaseOrder class, I could have easily not included a VendorAddress property since it could be retrieved from the Vendor, however as you will see as we progress, the vendors will be stored in an application wide collection, which can change over time, addresses, phone numbers, all these can change, and if you try to reference current data onto an old document, you can have problems. Only reference data when you know that the referenced data is not subject to future change.

Moving Forward

On the next installment, we will begin delving into the UI aspects of our application. Creating an MDI platform, using a TaskBar icon, and starting up with a loading splash screen. If this interests you, stick with it, because things will start to get even more interesting as we progress.

Points of Interest

  • Basic object inheritance
  • Overloaded methods in inherited classes

History

  • Original - 10/28/2015

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseExcellent Work Pin
Member 99709897-Jun-17 17:23
Member 99709897-Jun-17 17:23 
QuestionDownload Link Pin
Juzer3-Dec-15 7:06
Juzer3-Dec-15 7:06 
AnswerRe: Download Link Pin
stebo07283-Dec-15 9:19
stebo07283-Dec-15 9:19 
QuestionClear Article Pin
Charl30-Oct-15 3:18
Charl30-Oct-15 3:18 
PraiseMy Vote of 5ed Pin
JayantaChatterjee29-Oct-15 18:14
professionalJayantaChatterjee29-Oct-15 18:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.