I have found two primary libraries for programmatically manipulating PDF files; PdfBox and iText. These are both Java libraries, but I needed something I could use with C Sharp. Well, as it turns out there is an implementation of each of these libraries for .NET, each with its own strengths and weaknesses:
Some Navigation Links:
PdfBox - .Net version
The .NET implementation of PdfBox is not a direct port - rather, it uses IKVM to run the Java version inter-operably with .NET. IKVM features an actual .net implementation of a Java Virtual Machine, and a .net implementation of Java Class Libraries along with tools which enable Java and .Net interoperability.
PdfBox’s dependency on IKVK incurs a lot of baggage in performance terms. When the IKVM libraries load, and (I am assuming) the “’Virtual’ Java Virtual Machine” spins up, things slow way down until the load is complete. On the other hand, for some of the more common things one might want to do with a PDF programmatically, the API is (relatively) straightforward, and well documented.
When you run a project which uses PdfBox, you WILL notice a lag the first time PdfBox and IKVM are loaded. After that, things seem to perform sufficiently, at least for what I needed to do.
Side Note: iTextSharp
iTextSharp is a direct port of the Java library to .Net.
iTextSharp looks to be the more robust library in terms of fine-grained control, and is extensively documented in a book by one of the authors of the library, iText in Action (Second Edition)
. However, the learning curve was a little steeper for iText, and I needed to get a project out the door. I will examine iTextSharp in another post, because it looks really cool, and supposedly does not suffer the performance limitations of PdfBox.
Getting started with PdfBox
Before you can use PdfBox, you need to either build the project from source, or download the ready-to-use binaries. I just downloaded the binaries for version 1.2.1 from this helpful gentleman’s site, which, since they depend on IKVM, also includes the IKVM binaries. However, there are detailed instruction for building from source on the PdfBox site. Personally, I would start with the downloaded binaries to see if PdfBox is what you want to use first.
Important to note here: apparently, the PdfBox binaries are dependent upon the exact dependent DLL’s used to build them. See the notes on the PdfBox .Net Version page.
Once you have built or downloaded the binaries, you will need to set references to PdfBox and ALL the included IKVM binaries in your Visual Studio Project. Create a new Visual Studio project named “PdfBoxExamples” and add references to ALL the PdfBox and IKVM binaries. There are a LOT. Deal with it. Your project references folder will look like the picture to the right when you are done.
The PdfBox API is quite dense, but there is a handy reference at the Apache Pdfbox site. The PDF file format is complex, to say the least, so when you first take a gander at the available classes and methods presented by the PDF box API, it can be difficult to know where to begin. Also, there is the small issue that what you are looking at is a Java API, so some of the naming conventions are a little different. Also, the PdfBox API often returns what appear to be Java classes. This comes back to that .Net implementation of the Java Class libraries I mentioned earlier.
Things to Do with PdfBox
It seems like there are three common things I often want to do with PDF files: Extract text into a string or text file, split the document into one or more parts, or merge pages or documents together. To get started with using PdfBox we will look at extracting text first, since the set up for this is pretty straightforward, and there isn’t any real Java/.Net weirdness here.
To do this, we will call upon two PdfBox namespaces (“Packages” in Java, loosely), and two Classes:
The namespace org.apache.pdfbox.pdmodel gives us access to the PDDocument class and the namespace org.apache.pdfbox.util gives us the PDFTextStripper class.
In your new PdfBoxExamples project, add a new class, name it “PdfTextExtractor," and add the following code:
The PdfTextExtractor Class
using System;
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.util;
namespace PdfBoxExamples
{
public class pdfTextExtractor
{
public static String PDFText(String PDFFilePath)
{
PDDocument doc = PDDocument.load(PDFFilePath);
PDFTextStripper stripper = new PDFTextStripper();
return stripper.getText(doc);
}
}
}
As you can see, we use the PDDocument class (from the org.apache.pdfbox.pdmodel namespace) and initialize is using the static .load method defined as a class member on PDDocument. As long as we pass it a valid file path, the .load method will return an instance of PDDocument, ready for us to work with.
Once we have the PDDocument instance, we need an instance of the PDFTextStripper class, from the namespace org.apache.pdfbox.util. We pass our instance of PDDocument in as a parameter, and get back a string representing the text contained in the original PDF file.
Be prepared. PDF documents can employ some strange layouts, especially when there are tables and/or form fields involved. The text you get back will tend not to retain the formatting from the document, and in some cases can be bizarre.
However, the ability to strip text in this manner can be very useful, For example, I recently needed to download an individual PDF file for each county in the state of Missouri, and strip some tabular data our of each one. I hacked together an iterator/downloader to pull down the files, and the, using a modified version of the text stripping tool illustrated above and some rather painful Regex, I was able to get what I needed.
At the simplest level, suppose you had a PDF file and you wanted to split it into individual pages. We can use the Splitter Class, again from the org.apache.pdf.util namespace. Add another class to you project, named PDFFileSplitter, and copy the following code into the editor:
The PdfFileSplitter Class
using org.apache.pdfbox.pdmodel;
using org.apache.pdfbox.util;
namespace PdfBoxExamples
{
public class PDFFileSplitter
{
public static java.util.List SplitPDFFile(string SourcePath,
int splitPageQty = 1)
{
var doc = PDDocument.load(SourcePath);
var splitter = new Splitter();
splitter.setSplitAtPage(splitPageQty);
return (java.util.List)splitter.split(doc);
}
}
}
Notice anything strange in the code above? That’s right. We have declared a static method with a return type of java.util.List. WHAT? This is where working with PdfBox and more importantly, IKVM becomes weird/cool. Cool, because I am using a direct Java class implementation in Visual Studio, in my C# code. Weird, because my method returns a bizarre type (from a C# perspective, anyway) that I was unsure what to do with.
I would probably add to the above class so that the splitter persisted the split documents to disk, or change the return type of my method to object[], and use the .ToArray() method, like so:
The PdfFileSplitter Class (improved?)
public static object[] SplitPDFFile(string SourcePath,
int splitPageQty = 1)
{
var doc = PDDocument.load(SourcePath);
var splitter = new Splitter();
splitter.setSplitAtPage(splitPageQty);
return (object[])splitter.split(doc).toArray();
}
In any case, the code in either example loads up the specified PDF file into a PDDocument instance, which is then passed to the org.apache.pdfbox.Splitter, along with an int parameter. The output in the example above is a Java ArrayList containing a single page from your original document in each element. Your original document is not altered by this process, by the way.
The int parameter is telling the Splitter how many pages should be in each split section. In other words, if you start with a six-page PDF file, the output will be three two-page files. If you started with a 5-page file, the output would be two two-page files and one single-page file. You get the idea.
Something slightly more useful might be a method which accepts an array of integers as a parameter, with each integer representing a page number within a group to be extracted into a new, composite document. For example, say I needed pages 1, 6, and 7 from a 44 page PDF pulled out and merged into a new document (in reality, I needed to do this for pages 1, 6, and 7 for each of about 200 individual documents). We might add a method to our PdfFileSplitter Class as follows:
The ExtractToSingleFile Method
public static void ExtractToSingleFile(int[] PageNumbers,
string sourceFilePath, string outputFilePath)
{
var originalDocument = PDDocument.load(sourceFilePath);
var originalCatalog = originalDocument.getDocumentCatalog();
java.util.List sourceDocumentPages = originalCatalog.getAllPages();
var newDocument = new PDDocument();
foreach (var pageNumber in PageNumbers)
{
// Page numbers are 1-based, but PDPages are contained in a zero-based array:
int pageIndex = pageNumber - 1;
newDocument.addPage((PDPage)sourceDocumentPages.get(pageIndex));
}
newDocument.save(outputFilePath);
}
Below is a simple example to illustrate how we might call this method from a client:
Calling the ExtractToSingleFile Method:
public void ExtractAndMergePages()
{
string sourcePath = @"C:\SomeDirectory\YourFile.pdf";
string outputPath = @"C:\SomeDirectory\YourNewFile.pdf";
int[] pageNumbers = { 1, 6, 7 };
PDFFileSplitter.ExtractToSingleFile(pageNumbers, sourcePath, outputPath);
}
Limit Class Dependency on PdfBox
It is always good to limit dependencies within a project. In this case, especially, I would want to keep those odd Java class references constrained to the highest degree possible. In other words, where possible, I would attempt to either return standard .net types from my classes which consume the PdfBox API, or otherwise complete execution so that client code calling upon this class doesn’t need to be aware of IKVM, or funky C#/Java hybrid types.
Or, I would build out my own “PdfUtilities” library project, within which objects are free to depend upon and intermix this Java hybrid. However, I would make sure public methods defined within the library itself accepted and returned only standard C# types.
In fact, that is precisely what I am doing, and I’ll look at that in a following post.
John on Google CodeProject
I bumped into a question on StackOverflow this evening that I felt might make a short post. Accompanying code is available at my Github repo.
The guy who posted observed that the standard .net DataGridview control provides a helpful little glyph next to the row which contains the active cell:

The original poster of the question was wondering how he might include a similar glyph to indicate the active column as well. My problem with that is that there already exists an option for an arrow-like glyph in a column header. Unfortunately, THAT glyph, by convention, tends to mean “Click here to sort on this column.”
That does NOT mean that the OP was off-base, though. I can think of many cases where it would be handy to have some sort of reference to the active column in addition to the active row.
Emphasize the Active Column with the DataGridViewColumn.HeaderCell.Style property
One way to approach this is to simply cause the text in the header cell to be bold when the user navigates to a cell within that column. We can create a class which inherits from DataGridView, and take advantage of the CellEnter Event to cause this to happen:

In the following code, we have a member variable which holds a reference to the last active column. In our constructor, we initialize this column object so that when the control is instantiated, the reference is not null.
We also add an event handler to catch the CellEnter event locally. When this event fires, the handler (dgvControl_CellEnter) catches it, and makes a call to our final method, OnColumnFocus. This method accepts a column index as a parameter, and uses the index to identify the new active column. From there, we can use the HeaderCell.Style property to set the font to “bold” for this particular column.
In our constructor, note that we have to make an initial call to the OnColumnFocus method, so that the default starting column will be highlighted when the control is displayed at first. However, we have to check to see if there are actually any columns present first. This is because the Visual Studio Designer needs to be able to draw the empty control when we first place it on a form.
DataGridView: Cause the Active Column Header to Display Bold Text
class dgvControl : DataGridView
{
// hold a reference to the last active column:
private DataGridViewColumn _currentColumn;
public dgvControl() : base()
{
// Add a handler for the cell enter event:
this.CellEnter += new DataGridViewCellEventHandler(dgvControl_CellEnter);
// When the Control is initialized, instantiate the placeholder
// variable as a new object:
_currentColumn = new DataGridViewColumn();
// In case there are no columns added (for the designer):
if (this.Columns.Count > 0)
{
this.OnColumnFocus(0);
}
}
void dgvControl_CellEnter(object sender, DataGridViewCellEventArgs e)
{
this.OnColumnFocus(e.ColumnIndex);
}
void OnColumnFocus(int ColumnIndex)
{
// If the new cell is in the same column, do nothing:
if (ColumnIndex != _currentColumn.Index)
{
// Set up a custom font to represent the current column:
Font selectedFont = new Font(this.Font, FontStyle.Bold);
// Grab a reference to the current column:
var newColumn = this.Columns[ColumnIndex];
// Change the font to indicate status:
newColumn.HeaderCell.Style.Font = selectedFont;
// Set the font of the previous column back to normal:
_currentColumn.HeaderCell.Style.Font = this.Font;
// Set the current column placeholder to refer to the new column:
_currentColumn = newColumn;
}
}
}
What if I want More?
What if we want more than just bold text in the active header? Well, things get trickier. Manipulating the other properties of the HeaderCell Style require setting EnableHeaderVisualStyles to false. This has the unfortunate side effect of flattening out the styling which some from the Windows 7 GUI styles. The slight gradient and color scheme are replaced by a much flatter header. While we could work around this by overriding the OnPaint method (at least to a degree) and implementing our own painting scheme, the impact of the effect is not too disturbing.
For example, we could decide that in addition to bolding the text in the header, we will set the BackColor to a slightly darker gray:

To do this, we need only add three lines of code. First off, in our constructor, we set the EnableHeaderVisualStyles property to false. Next, in our OnColumnFocus method, we set the Style.BackColor property of the new active column to a darker shade of gray, and restore the previous active column to the default (empty) backcolor:
DataGridView: Cause the Active Column Header to Display Bold Text with a Darker Back Color:
class dgvControl : DataGridView
{
// hold a reference to the last active column:
private DataGridViewColumn _currentColumn;
public dgvControl() : base()
{
this.EnableHeadersVisualStyles = false;
// Add a handler for the cell enter event:
this.CellEnter += new DataGridViewCellEventHandler(dgvControl_CellEnter);
// When the Control is initialized, instantiate the placeholder
// variable as a new object:
_currentColumn = new DataGridViewColumn();
// In case there are no columns added (for the designer):
if (this.Columns.Count > 0)
{
this.OnColumnFocus(0);
}
}
void dgvControl_CellEnter(object sender, DataGridViewCellEventArgs e)
{
this.OnColumnFocus(e.ColumnIndex);
}
void OnColumnFocus(int ColumnIndex)
{
// If the new cell is in the same column, do nothing:
if (ColumnIndex != _currentColumn.Index)
{
// Set up a custom font to represent the current column:
Font selectedFont = new Font(this.Font, FontStyle.Bold);
// Grab a reference to the current column:
var newColumn = this.Columns[ColumnIndex];
// Change the font to indicate status:
newColumn.HeaderCell.Style.Font = selectedFont;
// Change the color to a slightly darker shade of gray:
newColumn.HeaderCell.Style.BackColor = Color.LightGray;
// Set the font of the previous column back to normal:
_currentColumn.HeaderCell.Style.Font = this.Font;
// Change the color of the previous column back to the default:
_currentColumn.HeaderCell.Style.BackColor = Color.Empty;
// Set the current column placeholder to refer to the new column:
_currentColumn = newColumn;
}
}
}
There are other options you might explore. In this post, we walked through some very basic ways to provide visual feedback to the user about their location within the DataGridView control.
The source code for this post is available at my Github repo.
CodeProject John on Google
John on Google CodeProject
Let’s face it. Managing date information within the .net framework (or any framework, really . . . Java is not much better) is a pain the the ass. Really. What makes it even worse is managing user data entry of date information. If that isn’t bad enough, there is a definite data type mismatch between the manner in which the .net framework represents date information, and the way relational databases handle dates.
The complete source code for this project (with a silly demo) is available on Github as a VS 2010 solution. Please feel free to fork, and if you make happy improvements, hit me with a pull request. There is plenty of room for improvement.
The Date Time Picker is Not Appropriate for All Situations . . . Because Sometimes, the Date is Unknown . . .
Sometimes we need to provide a means for users to enter a date if they have the information, and/or leave the date empty (null, if you will) until such time as they do. For example, in entering form data for a person, we may or may not know their Date of Birth. Do we really want to require some date, if we don’t know the correct birthdate? If we use the .Net DateTimePicker control, we have to. While there are hacks and workarounds for this, most require some sort of painful validation checking in our code
Never mind that the DateTimePicker is not the preferred data-entry choice for people who know how to tab through fields. Folks who are good, tab through fields, and enter data. When they come to a date field for which they have no data, they skip past it. They do NOT leave the default date there. And the DateTimePicker requires some date to be present. Not to mention the temptation to stop the tab-type-tab workflow by making you pick from a popup calendar.
The .Net/Winforms Masked Textbox Sucks for Date Entry
That’s right. You heard me. Once upon a time, way back in MS Access, there existed a decent masking approach for entering date values into a textbox. MS seems to have tossed this aside, and delivered the lame control we have at our disposal in the .Net Framework. There are probably reasons for this, but I don’t know what they are. If you have tried using the MaskedTextbox control in a .net application for the purpose of masking date entry, you know what I mean. If you haven’t, go try it out. Then come back here, and see if my solution might be of help.
What I Needed for a Project at Work
I have been stuck working with a rather dull database application at work, and what I needed was a means to perform date entry with the following requirements:
- Null Values are allowed and desirable in the Database backend.
- There will be many places where date-entry is performed, across many forms (it is a date-heavy application related to property management), so the date entry control must be easy to toss onto a form and build around, without a bunch of bs validation and string parsing every time.
- Null values are allowed, but other invalid entries are not.
- All date entry will be performed using the USA-centric mm/dd/yyyy format.
- The time component is irrelevant, or will be handled as a separate entry using a different control
- Given entry of a valid date string, a .net DateTime object should be retrieved from the control.
- Only dates between 1900 and 2099 will be recognized as valid.
What I wanted, for this project, and for general use in whatever other context pops up, was a means to allow the typing in of a date into a text box, validation of the result as a valid date, and the ability for the client code to simply retrieve a nullable datetime object.
For the purposes of my project, I have achieved these requirements. The control has flaws to this point, in terms of general use (limiting the acceptable centuries comes immediately to mind), but it is a starting point.
My Solution: The MaskedDateTextbox Control
I set out to replicate the user-facing aspects of the venerable VBA Masking approach found in the MS Access Textbox, and join it with the .net type system such that a text string date representation could be validated, and then returned to the client code in a useful form, even if null was present.
Inheriting From MaskedTextbox
I began by inheriting from the crusty .net MaskedTextBox control. First order of business was to define the mask we would be using for date entry. For my purposes, I needed to get this done fast, and the project I am working on will only ever require dates in the US-style mm/dd/yyyy format, so I opted to basically fix this as the only mask available.
But what about globalization?
As you can see, for this work-specific implementation, I thwart attempts to change to a different mask, because the code to this point depends upon a final output format of mm/dd/yyyy Anything else will require more work. That said, it would be a small issue to adapt the code to utilize a different date format. I didn’t have time to build in the kind of flexibility which would allow the mask, and the required validations and text manipulations, to be variable. But adapting the code to recognize and work with some other format should be a small problem.
In any case, the following code defines a class, MaskedDateTextBox, which inherits from the .net MaskedTextBox. As you can see, I have defined a few private members, a couple event handlers, a constructor overload, and overridden the OnMaskChanged method. Most importantly, I have set the mask and the prompt character to the standard format, using private constants. The mask format 00/00/0000 requires integers where the zero placeholders are, and ignores non-integer entries.
The Beginnings of the MaskedDateTextBox Class:
public class MaskedDateTextBox : MaskedTextBox
{
// Default setting is to require a valid date string before allowing
// the user to navigate away from the control:
public bool _RequireValidEntry = true;
// The default mask is traditional, USA-centric mm/dd/yyyy format.
private const string DEFAULT_MASK = "00/00/0000";
private const char DEFAULT_PROMPT = '_';
// A flag is set when control initialization is complete. This
// will be used to determine if the Mask property of the control
// (inherited from the Base class) can be changed.
private bool _Initialized = false;
public MaskedDateTextBox() : this(true) { }
public MaskedDateTextBox(bool RequireValidEntry = true) : base()
{
// This is the only mask that will work in the current implementation:
this.Mask = DEFAULT_MASK;
this.PromptChar = DEFAULT_PROMPT;
// Handle Events:
this.Enter +=new EventHandler(MaskedDateTextBox_SelectAllOnEnter);
this.PreviewKeyDown +=new PreviewKeyDownEventHandler(MaskedDateBox_PreviewKeyDown);
// prevent further changes to the mask:
_Initialized = true;
}
protected override void OnMaskChanged(EventArgs e)
{
if (_Initialized)
{
throw new NotImplementedException("The Mask is not chageable in this control");
}
}
}
Note the boolean member _IsInitialized. This is set to true immediately after the mask is set in the constructor. From this point forward, attempts by client code to change the mask will fail, and throw a not implemented exception when the OnMaskChanged method is called by the base.
Also note the optional Constructor parameter RequireValidEntry, which is used to set the local member _RequireValidEntry. This matters a little further along. As it is, the constructor parameter defaults to true, even when the default constructor is used. However, there are cases in which one might prefer to handle invalid date entry from the client code, and this parameter (and the member it sets) come into play at that point. More on this in a minute.
Straightening Out The Date
The core of this control, and the reason I needed to build it, are evidenced in the following logic, which examines user input, and attempts to get it into the proper mm/dd/yyyy format. The trick here is that some people may enter 1/1/2012, others may enter 01/01/2012, and still others may try to use 1-1-12. In my mind, all of these should resolve to the same date.
Add this code to the MaskedDateTextBox class:
Correcting Date Text Entry to Match the Standard Format:
void CorrectDateText(MaskedTextBox dateTextBox)
{
// Replace any odd date separators with the mm/dd/yyyy Standard:
Regex rgx = new Regex(@"(\\|-|\.)");
string FormattedDate = rgx.Replace(dateTextBox.Text, @"/");
// Separate the date components as delimited by standard mm/dd/yyyy formatting:
string[] dateComponents = FormattedDate.Split('/');
string month = dateComponents[0].Trim(); ;
string day = dateComponents[1].Trim();
string year = dateComponents[2].Trim();
// We require a two-digit month. If there is only one digit, add a leading zero:
if (month.Length == 1)
month = "0" + month;
// We require a two-digit day. If there is only one digit, add a leading zero:
if (day.Length == 1)
day = "0" + day;
// We require a four-digit year. If there are only two digits, add
// two digits denoting the current century as leading numerals:
if (year.Length == 2)
year = "20" + year;
// Put the date back together again with proper delimiters, and
dateTextBox.Text = month + "/" + day + "/" + year;
}
Note that we pass this method a reference to a MaskedTextBox. I could have accessed the properties of the containing MaskedTextBox class directly, but it seemed cleaner this way. Also, I may decide to extract this method out into its own class (DateStringFormatter?).
OK. So, we will use the previous method from a number of locations. First off, directly, and the user is entering text. We want to force the user’s input into the proper format as they type (for example, if they separate their date parts with dashes instead of slashes). For this, we will handle the PreviewKeyDown Event. Remember, in our constructor, we added a handler for the PreviewKeyDown Event? Now we’re going to handle that event:
Handle User Input as it Happens with PreviewKeyDown Event:
protected virtual void MaskedDateBox_PreviewKeyDown(object sender,
PreviewKeyDownEventArgs e)
{
MaskedTextBox txt = (MaskedTextBox)sender;
// Check for common date delimiting characters. When encountered,
// adjust the text entry for proper date formatting:
if (e.KeyCode == Keys.Divide
|| e.KeyCode == Keys.Oem5
|| e.KeyCode == Keys.OemQuestion
|| e.KeyCode == Keys.OemPeriod
|| e.KeyValue == 190
|| e.KeyValue == 110)
// If any of the above key values are encountered, apply a formatting
// check to the text entered so far, and make adjustments as needed.
this.CorrectDateText(txt);
}
In the above, we test for the various keys which might indicate the wrong sorts of date delimiter inputs. If any of these undesirable characters are found, we make a quick call to our CorrectDateText method, and straighten things out on the fly, so to speak.
Validate the User Input
Next, we want to perform a check when the user navigates away from the control, to be sure that what they have entered is, in fact, a valid date, as well as to perform any additional re-formatting required. We need three methods to do this. The OnLeave method, which overrides the same method on the base class, uses the boolean function IsValidDate to see if the string represented in the control is a valid date. If so, the overridden method calls the OnLeave method on the base and allows the user to navigate away from the control. If the date is not valid, then the OnInvalidDateEntry method is executed, which raises the InvalidDateEntered event, and depending upon the state of _RequireValidEntry, returns the user to the control to correct the issue.
Testing for a Valid Date Entry Before Leaving the Control
bool IsValidDate(MaskedTextBox dateTextBox)
{
// Remove delimiters from the text contained in the control.
string DateContents = dateTextBox.Text.Replace("/", "").Trim();
// if no date was entered, we will be left with an empty string
// or whitespace.
if (!string.IsNullOrEmpty(DateContents) && DateContents != "")
{
// Split the original date into components:
string[] dateSoFar = dateTextBox.Text.Split('/');
string month = dateSoFar[0].Trim(); ;
string day = dateSoFar[1].Trim();
string year = dateSoFar[2].Trim();
// If the component values are of the proper length for mm/dd/yyyy formatting:
if (month.Length == 2
&& day.Length == 2
&& year.Length == 4
&& (year.StartsWith("19") || year.StartsWith("20")))
{
// Check to see if the string resolves to a valid date:
DateTime d;
if (!DateTime.TryParse(dateTextBox.Text, out d))
{
// The string did NOT resolve to a valid date:
return false;
}
else
// The string resolved to a valid date:
return true;
}
else
{
// The Components are not of the correct size, and automatic adjustment
// is unsuccessful:
return false;
} // End if Components are correctly sized
}
else
// The date string is empty or whitespace - no date is a valid return:
return true;
}
protected override void OnLeave(EventArgs e)
{
// Perform a final adjustment of the text entry to fit the mm/dd/yyyy format:
this.CorrectDateText(this);
// If the entry is a valid date, fire the leave event. We are done here.
if (this.IsValidDate(this))
{
base.OnLeave(e);
}
else
{
this.OnInvalidDateEntry(this, new InvalidDateTextEventArgs(this.Text.Trim()));
// if a valid date entry is not required, the user is free to navigate away
// from the control:
if (!_RequireValidEntry)
{
base.OnLeave(e);
}
}
}
protected virtual void OnInvalidDateEntry(object sender, InvalidDateTextEventArgs e)
{
if (_RequireValidEntry)
{
// Force the user to address the problem before
// navigating away from the control:
MessageBox.Show(e.Message);
this.Focus();
this.MaskedDateTextBox_SelectAllOnEnter(this, new EventArgs());
}
// Raise the invalid entry event either way. Client code can determine
// if and how invalid entry should be dealt with:
if (InvalidDateEntered != null)
{
InvalidDateEntered(this, e);
}
}
Define a Custom Event Handler: InvalidDateTextEventArgs
We hooked up the InvalideDateEntered event in our constructor. However, I defined a custom EventArgs class which is required by the InvalidDateEntered Event. Define the following class in a separate code file:
A Custom EventArgs Class: InvalidDateTextEventArgs
using System;
namespace MaskedDateEntryControl
{
public class InvalidDateTextEventArgs : EventArgs
{
private string _Message = ""
+ "Text does not resolve to a valid date. "
+ "Enter a date in mm/dd/yyyy format, "
+ "or clear the text to represent an empty date.";
private string _InvalidDateString = "";
public InvalidDateTextEventArgs(string InvalidDateString) : base()
{
_InvalidDateString = InvalidDateString;
}
public InvalidDateTextEventArgs(string InvalidDateString, string Message)
: this(InvalidDateString)
{
_Message = Message;
}
public String Message
{
get { return _Message; }
set { _Message = value; }
}
public String InvalidDateString
{
get { return _InvalidDateString; }
}
}
}
Return a Nullable DateTime Object
Ok. Remember one of my requirements was the ability to retrieve a DateTime object (or null) directly from the MaskedDateTextBox control? This next bit of code is where we do that. Add this code to the MaskedDateTextBox control right after the OnInvalidDateEntry method:
A Property Which Returns a Nullable DateTime Object Based on User Input:
public DateTime? DateValue
{
get
{
DateTime d;
DateTime? Result = null;
if (DateTime.TryParse(this.Text, out d))
{
Result = d;
}
return Result;
}
set
{
string DateString = "";
if (value.HasValue)
DateString = value.Value.ToString("MM/dd/yyyy");
this.Text = DateString;
}
}
Using BeginInvoke to Overcome a Deficiency in the .Net MaskedTextBox Control:
So, the thing which was driving me crazy about this control (and the .net MaskedTextBox from which it derives) was that there did NOT seem to be a way to cause the text in the control to be selected upon entry, such as when an invalid string was entered, and the user is returned to the control to fix it. I wanted the complete text existing in the control to be selected at such time as the user enters the control. Unfortunately, there is apparently a bug in the implementation of the MaskedTextBox control which prevents this from happening using the familiar Textbox.Select() method. As it turns out, there is a workaround,which requires the following code:
Use BeginInvoke to Select the Text contained in the MaskedTextBox Control (and derived controls):
void MaskedDateTextBox_SelectAllOnEnter(object sender, EventArgs e)
{
MaskedTextBox m = (MaskedTextBox)sender;
this.BeginInvoke((MethodInvoker)delegate()
{
m.SelectAll();
});
}
In the end, the MaskedDateTextBox as described here provided the solution for the moment. Is this a great control? No. It needs work. There are some limitations resulting from the need to get it done NOW which some design improvements would correct. What could be made better?
- Not restricted to s single date format
- Not restricted to years beginning with 19 and 20
- Probably some refactoring could be done with some of the nested conditionals
You can find the source code for this at my Github repo. Clone the VS2010 project if you want to see the complete code. If you see ways to improve it, please, feel free. If you succeed, hit me up with a pull request - I will happily merge your changes.
Compile for Distinctly Different Environment Configurations
CodeProject
NOTE: Source code for the example project in this article can be found at my Github repo.
I already understand most of this. Take me straight to the code!
I am currently working on a boring, enterprise-ey database application. You know the type – We needed it yesterday, it was built on the fly with minimal up-front design time, and pressure from on high to deliver SOMETHING right away, even if it sucks, they say, it will be better than what we have now. You KNOW, if you have read this far, that you have worked on projects such as I describe here as well. Probably many. You just don’t want to admit it. It’s OK. Admit it, and move forward. You’ll feel better.
Yes, yes, I know. This is where I am supposed to set management straight on the error of their ways, sell them on the idea of investing in an iterative design cycle, Agile/Test-Driven development methodology, the works.
Not gonna happen here, unfortunately.
SO. As the code progressed and bits and pieces of this monstrosity entered live testing and production, I am having to continue work on the rest of the application, adding features, fixing bugs, etc. Unfortunately, this application must be able to run in a couple of different scenarios:
- On my Dev machine at home (locally).
- On my Dev machine at work (locally).
- On a test server at work (Database and file persistence via LAN)
- On the production server at work (LAN, again)
- On a remote laptop with no LAN connection – files and data persisted locally until home
The database connection information is different for each of these scenarios. Also, this application persists copies of photographs and other files and stashes the directory information in a database record. The actual file location is different in each scenario as well (and hidden from the user). File access is performed through the application. In all cases, the settings required to achieve all this should NOT be available to the user (although ultimately, some level of admin functionality might be incorporated. But not right now . . . ).
My Solution – Set Application Settings at Compile Time
I will say right here that this is most likely a hack solution to what is ultimately an application design issue. I have heard it said that the use of conditional compilation is often a strong code “smell” indicating a potential area for redesign. However, in my case, I needed a fast answer.
I have identified five possible environments within which the application must run, each of which require the same code base, but different application settings. For this example, I will leave the default Debug and Release configurations as they are, and simply create two additional configurations, LIVE and TEST. Once I have done this, I can define Conditional Compilation symbols, and load different application settings depending upon which build configuration is running.
Set Up Build Configurations Using Build Configuration Manager
First, I will use the Build Configuration Manager within Visual Studio to create my Build Configurations. Configuration Manager allows you to create, customize, and manage build settings for all projects within the current solution. For this example, there is only a single project. Open Build/Configuration Manager . . .

From the drop-down menu in the Configuration Manager, select <New>:

I create a new Build Configuration named LIVE, and copy settings from the default Release configuration:

I then repeat these steps to create a TEST configuration (and as many others as I might need).
Since I am creating a simple example project for this post, there is only one project visible in the Configuration Manager list. However, if there were additional projects within this same solution, I would be able to assign different configurations to each, an indicate specific projects within the solution to build or not.
Define Conditional Compilation Symbols for Each Build Configuration
Now we need to define Conditional Compilation symbols for each build configuration. Open the Project Properties window from the solution explorer, and select the “Build” tab. in the dropdown list of available configurations, you will now see the default Debug and Release options, as well as your newly defined LIVE and TEST configurations. First we will select the LIVE configuration, and add a Conditional Compilation symbol in the space provided. Because I like to keep things simple, we’ll use “LIVE” as our symbol:

Then select the TEST configuration from the drop-down menu, and repeat the same steps, typing “TEST” into the Conditional compilation symbols space.
We have now defined a symbol for each of our two build options. Now let’s look at how we can use these in our application to load build specific application settings at compile time.
Define Version-Specific Resources, and General Application Settings
Ok. Here’s the meat and potatoes of the whole thing. First, we need to define our application settings. One of the reasons I chose to take this approach is that application settings can be accessed and modified without having to recompile the application. Same with resource files. For ease of making changes to a compiled application which is being used for production, I am going to define a couple of output file paths, and save them as resource files. I will also create a string message for each version, which we will use for illustrative purposes in this example.
First, create text files with the following text, either in your preferred text editor, or using the “Add New Text File” option in the Resource Manager:
| File Name: |
Text Content: |
| LiveOutputFolderPath.txt |
C:\LiveOutputFolder\
|
| TestOutputFolderPath.txt |
C:\TestOutputFolder\
|
| LiveVersionMessage.txt |
This is the LIVE version of the Application
|
| TestVersionMessage.txt |
This is the TEST version of the application
|
Add the resource files to your project in the Resource Designer:

Next, define version-agnostic Application Settings using the Settings Designer like so (leave the values empty – these will be set at compile-time). Make sure to set the scope for each setting to “Application” and not “User”. Name one setting “BuildVersionMessage” and the other “OutputFolderPath”:

Ok. See that “View Code” menu item near the top of the Settings Designer window? Click on that. You should see a code file open to display a partial class file for the Settings Designer. This is where we get down to business.
Code: Setting Application Settings Values at Compile Time
When the Settings.cs file first opens, you will see some VS-generated code in the file. I deleted all that – we’re not using it here. Replace it with the following code (the complete source code for this example project is available from my Github repo):
8/19/2012 8:00 AM - UPDATE: I added similar code for the default “Debug” and “Release” configurations to the example project in my Github repo. The only difference is that these two methods explicitly specify Environment.CurrentDirectory as the root directory instead of using a resource file to grab the directory path. If you run the following code as-is under the Debug or Release build configurations, things won’t work the way you expect!
1: using System.Diagnostics;
2:
3: namespace WindowsFormsApplication1.Properties
4: {
5:
6: internal sealed partial class Settings
7: {
8: public Settings()
9: {
10: // Each method corresponds to a build version. We call both methods, because
11: // the conditional compilation will only compile the one indicated:
12: this.SetLiveApplicationSettings();
13: this.SetTestApplicationSettings();
14: }
15:
16: [Conditional("LIVE")]
17: private void SetLiveApplicationSettings()
18: {
19: // Set the two Settings values to use the resource files designated
20: // for the LIVE version of the app:
21: this["BuildVersionMessage"] = Resources.LiveVersionMessage;
22: this["OutputFolderPath"] = Resources.LiveOutputFolderPath;
23: }
24:
25:
26: [Conditional("TEST")]
27: private void SetTestApplicationSettings()
28: {
29: // Set the two Settings values to use the resource files designated
30: // for the TEST version of the app:
31: this["BuildVersionMessage"] = Resources.TestVersionMessage;
32: this["OutputFolderPath"] = Resources.TestOutputFolderPath;
33: }
34: }
35: }
Note the use of the Conditional Attribute For the SetLiveApplicationSettings and SetTestApplicationSettings methods. Because we have used this attribute, and made reference to our version-specific Compilation Symbols for each, the code for either of these methods will only be compiled for that specific version identified in the Conditional Attribute. We call both methods from the Settings() constructor, so that whichever version is compiled will be called during initialization.
What is important here is to get the string representations for each of the Compilation Symbols correct, as well as the Setting names, used as keys to access the specific Settings properties. Misspellings here will cause the code to fail.
Demonstration of Conditional Compilation
To demonstrate how this works, create a simple Form in the designer, like this:

Name the Label “lblHeader” and the Button “btnCopyFile” (yes, I still go a little Hungarian with my control names. Makes them easier to find with Intellisense, dammit . . .).
Now, use this code in the form (the complete source code for this article is available at my GitHub repo):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.btnCopyFile.Click += new System.EventHandler(this.btnCopyFile_Click);
}
private void Form1_Load(object sender, EventArgs e)
{
// The BuildVersionMessage setting will be set at compile time:
this.lblHeader.Text = Properties.Settings.Default.BuildVersionMessage;
}
private void btnCopyFile_Click(object sender, EventArgs e)
{
this.CopyFile();
}
private void CopyFile()
{
// The correct output file path will be defined at compile time,
// and made available through the settings file:
string outputDirectory = Properties.Settings.Default.OutputFolderPath;
// Make sure the directory exists:
if (!Directory.Exists(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
}
using (var fileDialog = new OpenFileDialog())
{
fileDialog.InitialDirectory =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
fileDialog.Multiselect = false;
if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string oldFullFileName = fileDialog.FileName;
string safeFileName = fileDialog.SafeFileName;
// Create a new File Name using the output directory
// defined at compile time:
string newFullFileName = outputDirectory + safeFileName;
// Check to see if a file with the same name already exists:
if (File.Exists(newFullFileName))
{
// File.Copy won't let us overwrite. Since the user has no knowledge
// of this directory, we just delete the old, and save the new:
File.Delete(newFullFileName);
}
// Copy the file into our secret hidden directory:
File.Copy(oldFullFileName, newFullFileName);
// ...
// Add code here to persist the file path and other information
// to the data store for access within the application . . .
// ...
}
}
}
}
}
Now, build and run the application under each of the LIVE and TEST Build Configurations. When we set the build configuration to TEST and run, the form opens as follows:
If we press the Copy File button, select a file, and hit OK, the file will be saved in the directory specified in the file we named TestOutputDirectory.txt. We can go to that directory in Windows Explorer and sure enough, there is a copy of the original file. Likewise, the text displayed in the form label is the text we saved in the TestVersionMessage.txt file.

When switch to the LIVE build configuration, we see similar results. What’s cool here is that if we needed to, we could open the text files which serve as out string resources and modify the directory paths or message text, save, and these changes would be incorporated into our running application without recompiling. While this is not a new thing, we still maintain the integrity of our build-specific settings – the LIVE version will load those settings specific to that build, and likewise the TEST version.
Wrapping up
While this example has been simplified for the purpose of explaining what I did, the reality is that I was able to address the varying database connection and output folder requirements of my distinct application versions and tailor each to the environment in which it would run. When I compile and run the application on my home machine, I simply select the HOME build configuration. No messing about setting database connection settings or file directories. Likewise when I have added some new features to the production build. I simply select the PRODUCTION build configuration, and the network serve database connection and LAN network shares are all appropriately set so that code which requires those settings simply works.
Useful Links:
More information on Conditional Compilation and Conditional Methods in C#/VS:
Source code for example project:
John on Google
The GroupedList Control Container
CodeProject
This post is part two of a short series on extending the Winforms Listview control. If you missed the previous post, you can review it HERE. Also, the Source Code for this project can be found in my GitHub repo.
In our previous post, we examined the first component of what I am calling the “GroupedList Control” – essentially, a list of contained and extended Listview controls which act as independent groups. Individual ListGroups (which is how I refer to them) may contain independent column headers, and are expandable/collapsible, much like what I believe is called a “slider” control.
A brief note – I am posting somewhat abbreviated code here. I have omitted many common overloads and other features we might discuss in a future post. For now, the code posted here contains only the very core functionality under discussion. The Source, however, contains all my work so far on this control.
Also note – the GroupedListControl arose out of my need for a quick-and-dirty combination of the functionality of the Winforms Listview and a Treeview. A group of columnar lists which could be independently expanded or collapsed.
A Quick Look at a Very Plain Demo:
In the last post, we had assembled our basic ListGroup component, which is essentially an extension of the Winforms Listview control, modified to handle some events related to column and item addition and removal. Where we left off, it was time to assemble our container, the GroupedListControl.
I figured the quickest way to accomplish what I needed (remember – under the gun, here) would be to extend the FlowLayoutPanel such that I could use this ready-made container to manage a collection of ListGroup controls, stack them vertically, and such. There were a few issues with this approach that we will discuss in a bit. First, let’s look at the basic code required to bring the control to life:
The GroupedList Control – Basic Code:
public class GroupListControl : FlowLayoutPanel
{
public GroupListControl()
{
// Default configuration. Adapt to suit your needs:
this.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.AutoScroll = true;
this.WrapContents = false;
// Add a local handler for the ControlAdded Event.
this.ControlAdded += new ControlEventHandler(GroupListControl_ControlAdded);
}
/// <summary>
/// Handles the ControlAdded Event for the current instance.
/// </summary>
void GroupListControl_ControlAdded(object sender, ControlEventArgs e)
{
ListGroup lg = (ListGroup)e.Control;
lg.Width = this.Width;
lg.GroupCollapsed += new ListGroup.GroupExpansionHandler(lg_GroupCollapsed);
lg.GroupExpanded += new ListGroup.GroupExpansionHandler(lg_GroupExpanded);
}
/// <summary>
/// Gets or Sets a boolean value indicating whether multiple ListGroups
/// may be in the expanded state at the same time. When set to true, the current expanded
/// ListGroup is collapsed when a new ListGroup is expanded.
/// </summary>
public bool SingleItemOnlyExpansion { get; set; }
/// <summary>
/// Handles the Expanded event for the current instance.
/// </summary>
void lg_GroupExpanded(object sender, EventArgs e)
{
// Grab a reference to the ListGroup which sent the message:
ListGroup expanded = (ListGroup)sender;
// If Single item only expansion, collapse all ListGroups in except
// the one currently exanding:
if (this.SingleItemOnlyExpansion)
{
this.SuspendLayout();
foreach (ListGroup lg in this.Controls)
{
if (!lg.Equals(expanded))
lg.Collapse();
}
this.ResumeLayout(true);
}
}
/// <summary>
/// Handles the Collapsed event for the current instance.
/// </summary>
void lg_GroupCollapsed(object sender, EventArgs e)
{
// No need.
}
/// <summary>
/// Expands all listgroups contained in the current instance.
/// </summary>
public void ExpandAll()
{
foreach (ListGroup lg in this.Controls)
{
lg.Expand();
}
}
/// <summary>
/// Collapses all ListGroups contained in the current instance.
/// </summary>
public void CollapseAll()
{
foreach (ListGroup lg in this.Controls)
{
lg.Collapse();
}
}
}
Of particular note here is the GroupListControl_ControlAdded Event Handler. Sadly, when one adds controls to the FlowLayoutPanel Controls collection, they are just that. The Controls property of the FlowLayout panel represents a ControlCollection object, which accepts a parameter of type (wait for it . . . ) Control.
I wanted MY GroupedListControl to contain a collection of ListGroup objects. However, I have not yet figured out a way to do this while retaining the functionality of the FlowLayout panel. As far as I can tell, we can’t narrow the type requirement of the native ControlCollection. One option I considered would be to add a new method to the class, named AddListGroup, which could then accept a parameter of type ListGroup, and pass THAT to the Controls.Add(Control) method. However, that seems a bit mindless, as the Controls.Add(0 method would remain publicly exposed, thus creating opportunity for confusion.
For now, I decided that those using this control will have to realize that passing anything other than a ListGroup object as the parameter will likely be disappointed in the performance of the control! It is less than elegant, but I didn’t have time to figure out a more elegant solution, and for the moment it works. I would love to hear suggestions for improvement.
The next thing to notice about the GroupListControl_ControlAdded method is that for each ListGroup we add, we are subscribing to the GroupExpanded and GroupCollapsed events sourced by each individual ListGroup. This is mainly because there are use cases in which we might want to limit group expansion to a single group at a time, such that expanding one group collapses any other expanded group. This is accomplished by providing the boolean SingleItemOnlyExpansion property. The GroupListControl_ControlAdded method checks the state of this property, and if true, collapses any expanded groups which are not equal to (as in, referencing the same object instance as) the current group (the “sender” in the method’s signature).
The last thing to note is the manner in which we set the width of each ListGroup in the GroupListControl_ControlAdded method. I tried setting the Dock property instead, and ran into difficulties with that.
Given the code above, you would think all that was pretty simple, no? Yeah. Right. A problem arose in the form of ugly scrollbars. The code above will run, and do everything represented. However, for the GroupedListControl to look like anything other than ass, we need to do something about the horizontal scrollbar which appears at the bottom of the GroupedListControl , due to the width of each ListGroup being essentially the same as the container control. This, I must say was initially giving me pains. The FlowLayoutPanel does not, apparently, afford us the ability to control the appearance of the horizontal and vertical scrollbars individually.
Some research on the interwebs yielded, after no small amount of digging, the following solution. Sadly, it involves Windows messages and API calls, neither of which I am particularly well-versed in. More sadly, I seem to have misplaced the link to where I found the solution. If YOU know where the concept below came from, please forward me a link, so I can link back, and attribute properly.
Add the following code to the end of the GroupedListControl class:
Handling Scrollbars by Intercepting Windows Messages:
/// <summary>
/// Consumed by the Win API calls below:
/// </summary>
private enum ScrollBarDirection
{
SB_HORZ = 0,
SB_VERT = 1,
SB_CTL = 2,
SB_BOTH = 3
}
/// <summary>
/// Disables the horizontal scrollbar in the primary container control.
/// Individual ListGroups within the GroupList have their own scrollbars
/// if needed.
/// </summary>
protected override void WndProc(ref System.Windows.Forms.Message m)
{
// Call to unmanaged WinAPI:
ShowScrollBar(this.Handle, (int)ScrollBarDirection.SB_HORZ, false);
base.WndProc(ref m);
}
/// <summary>
/// Imported from WinAPI: Method to control Scrollbar visibility.
/// </summary>
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ShowScrollBar(IntPtr hWnd, int wBar, bool bShow);
The above code essentially listens to windows messages, and when it “hears” one related to showing scrollbars in the FlowLayoutPanel base class, performs the appropriate action. in this case, some sort of WinAPI magic related to NOT showing the horizontal scrollbar.
Note that we WANT the vertical scrollbar to show up, anytime the height of the collected ListGroups exceeds the height of the GroupedList client area. But I decided I would prefer to have the horizontal scrolling option available within each individual ListGroup where needed, without the extra screen clutter of another horizontal scrollbar a the bottom of the container control.
Scroll Bars in the Grouped List Control (note horizontal scroll in individual ListGroup, and vertical scroll for container control . . .)

Summary
What we have done to this point is examine the core essentials of creating a composite control which provides some very basic behaviors I needed for a project at work. Some things to remember:
- The code in this and the previous post is somewhat abbreviated. For example, there are a number of overloads for the Add() method on both the ListViewItemCollection and the ListViewColumnCollection which we did not address here. They are, however, mostly addressed in the Source Code on Github. I will say not all the overloads have been properly tested.
- Another requirement I had for my control was the ability to detect Right-Mouse-Clicks on the column headers in each individual GroupedList. This capability is not built into the Listview control, and in fact it was a bit of an exercise to make it happen. More adventures with external calls to the WinApi. I will likely examine this in my next post.
- Populating the GroupedList control takes only a little more thought and planning that doing the same with a regular Listview. In many ways, it is akin to populating a two-tiered Treeview control. The Example project in the source code repo demonstrates this in a very, very basic way. I know thus far it has met my own needs rather nicely. I needed to make a large amount of data available to the user with a minimal number of clicks, and with minimal return trips to the database.
- I would love to hear about improvements, and especially where I have done something dumb. I am here to learn, so bring it. Feel free to fork the source, and please do put in a pull request for any changes or improvements you make.
I will try to follow up with a post about adding Right-Click detection for the ListGroup column Headers in a day or two. This enables us to deploy a different ContextMenuStrip when the user right-clicks on a columnheader vs. the standard context menu for the ListView Control.
Thanks for reading do far . . .
John on Google