For those of you that don't want to go out and buy a fancy business card utility, this may prove to be just the trick for designing easy colorful business cards. The source is included, so you can modify the program to design the card the way you wish.
There are a lot of aspects of C# that could be discussed relating to this application, but in this article I'll touch on two important features of the language. The first is how to use Dialogs in C# and the second is the BinaryFormatter feature. The UML Design is shown below:
This Design was reverse engineered using the WithClass 2000 UML Tool
Dialog Boxes
For you Visual C++ Programmers out there, Dialog boxes in C# will seem a bit different than the CDialog class you are used to. VB programmers will probably feel right at home. A Dialog box is just another form. The user can change the BorderStyle of the Form to FixedDialog to make it look more like a dialog. Also the user needs to assign the names of the OK and Cancel buttons in the form to the AcceptButton and CancelButton properties of the form as shown below:
These properties are used to tell the dialog to treat these buttons so that they have ok and cancel behavior. When a dialog is launched using ShowDialog, you can check the return value of the DialogResult object to see if the ok button was pressed:
protected void OpenCardDialog_Click (object sender, System.EventArgs e)
{
// Create a new Card Design Dialog and show it to the user
CardDialog myDialog = new CardDialog(MyCard);
if (myDialog.ShowDialog(this) == DialogResult.OK)
{
}
}
This is the basic technique for creating and showing modal dialogs. We construct a new dialog and pass the current business card information. The BusinessCard Object (MyCard) is used to initially populate the dialog with previous design information. The ShowDialog command keeps the dialog running modally until the user clicks Cancel or OK. When either of these buttons is pressed, the DialogResult is returned and can be checked to see how to proceed.
How do we get data from the dialog? In this example the data is extracted on the OK button Click Event and placed in the BusinessCard object:
protected void OKButton_Click (object sender, System.EventArgs e)
{
// Transfer Data to the BusinessCard Object
TheCard.FirstName = this.FirstNameEdit.Text;
TheCard.LastName = this.LastNameEdit.Text;
TheCard.Address = this.AddressEdit.Text;
TheCard.City = this.CityEdit.Text;
TheCard.State = this.StateEdit.Text;
TheCard.ZipCode = this.ZipEdit.Text;
TheCard.Phone = this.PhoneEdit.Text;
if (this.pictureBox1.Image != null)
{
TheCard.Picture = (Bitmap)this.pictureBox1.Image.Clone();
}
TheCard.Info = this.InfoEdit.Text;
TheCard.Email = this.EmailEdit.Text;
TheCard.Fax = this.FaxEdit.Text;
TheCard.LargeFont = LargeFont;
TheCard.SmallFont = SmallFont;
TheCard.PicturePath = PicturePath;
// Save the card data to a file
TheCard.SaveCard();
// seems like you have to do this next line in order to dismiss the dialog as OK
this.DialogResult = DialogResult.OK;
}
Also in the above routine the data is written out to a file using the BinaryFormatter.
BinaryFormatter
Did you know you could serialize your classes without having to make them serializable or write huge amounts of serialization code? (Visual C++ programmers know what I'm talking about). The BinaryFormatter allows you to output your class in a persistent file without changing your class at all. Below are the routines for reading and writing our business card:
To save a card using the BinaryFormatter, simply create a writeable stream and pass the stream with the class instance you wish to save into the BinaryFormatter.Serialize function. That's it! It's saved to a file. The BinaryFormatter saves all the private, public, protected member data of the class.
public void SaveCard()
{
try
{
// open the filestream
FileStream s = new FileStream(TheAppPath + "\\business_card1.bin", FileMode.Create, FileAccess.Write);
BinaryFormatter b = new BinaryFormatter(); // create the formatter
b.Serialize(s, this); // serialize the graph to the stream
s.Close();
}
catch(Exception exx)
{
System.Console.WriteLine(exx.ToString());
}
}
To read the card using the BinaryFormatter is just as easy. Create a stream for reading and use the BinaryFormatter's Deserialize function to read the string into a BusinessCard object:
public BusinessCard OpenCard()
{
try
{
// open the filestream
FileStream s = new FileStream(TheAppPath + "\\business_card1.bin", FileMode.Open, FileAccess.Read);
BinaryFormatter b = new BinaryFormatter(); // create the formatter
BusinessCard bc = (BusinessCard)b.Deserialize (s); // serialize the graph to the stream
s.Close();
return bc;
}
catch(Exception nocardsaved)
{
System.Console.WriteLine(nocardsaved.ToString());
return null;
}
}
BusinessCard Layout
If you wish to change the layout of the business card, you can alter the routine below:
public void PaintCard(Graphics g, Point offset)
{
// Draw Picture in upper left hand corner
if (Picture != null)
{
g.DrawImage(Picture, offset.X + 20, offset.Y + 20, 80, 80);
}
float sumHeight = 20f;
// Draw Name in Large Font
g.DrawString(FirstName + " " + LastName, LargeFont, Brushes.Black, (float)offset.X + 110.0f, (float)offset.Y + sumHeight);
sumHeight += LargeFont.Height + 3.0f;
// Draw Address
g.DrawString(Address, SmallFont, Brushes.Black, (float)offset.X + 110.0f, (float)offset.Y + sumHeight);
sumHeight += SmallFont.Height + 3.0f;
// Draw City, State, Zip
g.DrawString(City + ", " + State + " " + ZipCode, SmallFont, Brushes.Black,
(float)offset.X + 110.0f, (float)offset.Y + sumHeight);
// Draw Info in large Font
g.DrawString(Info, LargeFont, Brushes.Black, (float)offset.X + 110.0f, (float)offset.Y + sumHeight + 40.0f);
sumHeight += SmallFont.Height + 3.0f;
// Draw Phone and Fax towards the bottom of the card
g.DrawString("Phone: " + Phone + " Fax: " + Fax, SmallFont, Brushes.Black, (float)offset.X + 10.0f, (float)offset.Y + sumHeight + 70.0f);
sumHeight += SmallFont.Height + 3.0f;
// Draw Email under Phone and Fax
g.DrawString("Email: " + Email, SmallFont, Brushes.Black, (float)offset.X + 10.0f, (float)offset.Y + sumHeight + 70.0f);
}
This is the first phase of the business card application. The application was written to print on Avery 8376 Ink Jet Business cards. You may have to manipulate the margin constants a bit in order to get the cards to line up correctly. Anyway, have fun making cards, and email if you have any additional suggestions.