The PrintAdapters library provides a set of components that enable you to print some of the more common scrollable controls in the .NET Windows Forms control library: ListView, TreeView and RichTextBox. The features provided by PrintListView are also available in a similar component that can print any DataTable.
This how-to document will focus on working with just one of the PrintAdapters suite: PrintListView. PrintListView provides very good design time integration with Visual Studio that allows you to edit the style to be used when printing out your ListView, but it can also be accessed programmatically. We will develop a custom style using the designers, and then show how the same effect can be created from code.
As a basis for these examples we will take the SimpleListView sample provided with the PrintAdapters library, which provides us with a populated ListView to work with. Here's SimpleListView in the Visual Studio designer:

If we hit F5 to run the project we see:

Checking 'Landscape' and clicking 'Print Preview' gives us the following print preview:
Note that because we left the radio button 'Create Style from ListView Settings' selected, PrintListView has automatically created a style that mirrors the current ListView appearance, including Font settings, Colors, Column widths and icon and checkbox settings.
If we now return to Visual Studio, and add another PrintPreviewDialog and PrintListView component to the Form. Then:
Hit F5 and run this, and when you click on the new button you'll see the TableStyle in action (it is still the one picked up from ListView settings as in the Print Preview above).
Now, right click the TableStyle property in the Property grid and select Reset, then click the ellipsis ('...') to the right of the property to bring up the TableStyle editor. Note that the TableStyle in the preview has reverted to a basic grid as a result of the reset:

You can experiment with applying one of the predefined styles here by selecting from the list and clicking OK. When you run the sample and generate a print preview you should see the style applied to the printout.
We are going to build a style from scratch using the TableStyle designers however, so reset your TableStyle again to get back to the basic grid. Bring up the TableStyle designer and click on the 'Advanced' tab:

Before we go any further; a bit of background about how a TableStyle is built up. It has a BorderStyle, which can be edited in the designer by clicking on the BorderStyle property. This allows you to independently set the style, color and thickness of each edge of the border. This editor is used to edit the border of individual cells in a table as well as the border of the entire table area.

The TableStyle also has the following properties:
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
So we see from the above that each data row in the table can have a RowStyle. The first RowStyle in the RowStyleCollection is always applied to the header row, and subsequent RowStyles are applied in rotation to the data rows in the table. What does a RowStyle consist of?
RowStyle Properties
|
||||||||||||||||||||||||||||||
Finally we reach the individual CellStyle, which has the following properties:
|
||||||||||||||||||||||||||||||||||||||||||||||||||
Now that may seem pretty complicated, but we're going to show that we can produce quite complicated results with just a little bit of clicking in the designer. First, back to our project... we have a TableStyle which has been reset to the default i.e. no style settings set at all.
Starting with the designer in advanced mode again:

Click on the RowStyles property to bring up the editor:

Expand CellStyleDefault, and pick a BackGround color of LightGray and Font of Verdana 8pt:

On the same dialog, click on BorderStyles to bring up the border style editor, select Color Gray, then use the buttons around the edge of the Preview to turn the line for that edge on or off. Turn all but the bottom line off (Tip: to apply the new color and thickness settings to an edge, turn the line off, then back on again with the new settings):

Clicking OK until we return to the TableStyle editor, where we can see the effects of our editing:

Now we'll add two more RowStyles, one with a BackColor of Wheat, and the other with a BackColor of OldLace. Turn off all the edges on the BorderStyle for both.
Note the way that the two new RowStyles are repeatedly applied to the rows of the table, while the first RowStyle is only ever used for the first (header) row:

Lets make the Font of the left hand column Bold, and put a vertical line down between it and the second column. To do this we need to create a custom CellStyle for the first column in each of the RowStyles we've created.

Note: the ColumnIndexNumbering property of CellStyleMapping can hold values of either FromLeft or FromRight. We've left this at the default of FromLeft, but if we selected FromRight the 'Header LHS' style would be applied to the rightmost column in the final table. This can be useful if you're defining a TableStyle and want to highlight the righthand column in some way, but you don't yet know how many columns there will be in the table.

Click OK, and return to the TableStyle editor:

Repeat this process to add a CellStyle and CellStyleMapping to the other two RowStyles and we have:

As a final touch set SnapBordersToData to True:

If we now OK this and run the application, clicking on our new button on the main form gives us a print preview in the style we have just designed:

Now that we've been through the process of designing a style using the PrintAdapters designers, doing the same from code will make a lot more sense. Incidentally, if you just want to pick up the code that represents a certain style you have designed via the UI as a starting point, you can copy the code section for the PrintListView.TableStyle from the "Windows Form Designer generated code" section of your form. This is possible because PrintAdapters serializes out its state into code using the .NET CodeDom serialization mechanism.
Most of the following code is self-explanatory. If you're not familiar with the array initializer construct in VB.NET it can look a bit strange - basically, to instantiate and populate an array in one go we can use:
Dim arr As String() = New String() {"one", "two", "three"}
Apart from that, the process we're going through in code is exactly the same as the one we went through in the designer and should have identical results.
Putting the following VB.NET code in our button click handler will bypass the TableStyle we set up in the designer, and replace it with the one we're coding manually.
' Need to make sure PrintListView knows we're setting a
custom TableStyle
Me.PrintListView2.CustomStyle = True
' Create the standard Fonts we will use throughout the
table
Dim fontHeader As Font = New Font("Verdana", 8.25!,
System.Drawing.FontStyle.Regular)
Dim fontHeaderBold As Font = New Font("Verdana", 8.25!,
System.Drawing.FontStyle.Bold)
Dim fontBody As Font = New Font("Microsoft Sans Serif", 8.0!)
Dim fontBodyBold As Font = New Font("Microsoft Sans Serif", 8.0!,
System.Drawing.FontStyle.Bold)
' Some standard LineStyle objects for the BorderStyles
Dim lineNone As TMGDevelopment.Drawing.LineStyle = New
TMGDevelopment.Drawing.LineStyle(Color.Empty,
Drawing.Drawing2D.DashStyle.Solid, False, 1.0!, 0.0!, 0.0!)
Dim lineGray As TMGDevelopment.Drawing.LineStyle = New
TMGDevelopment.Drawing.LineStyle(Color.Gray, Drawing.Drawing2D.DashStyle.Solid,
True, 1.0!, 0.0!, 0.0!)
Dim lineBlack As TMGDevelopment.Drawing.LineStyle = New
TMGDevelopment.Drawing.LineStyle(Color.Black,
Drawing.Drawing2D.DashStyle.Solid, True, 1.0!, 0.0!, 0.0!)
' The BorderStyles for our header row, and special styles
for the left hand column
Dim bsGrayBottom As TMGDevelopment.Drawing.BorderStyle = New
TMGDevelopment.Drawing.BorderStyle(lineNone, lineGray, lineNone, lineNone)
Dim bsGrayBottomRHS As TMGDevelopment.Drawing.BorderStyle = New
TMGDevelopment.Drawing.BorderStyle(lineNone, lineGray, lineNone, lineGray)
Dim bsGrayRHS As TMGDevelopment.Drawing.BorderStyle = New
TMGDevelopment.Drawing.BorderStyle(lineNone, lineNone, lineNone, lineGray)
Dim bsBlack As TMGDevelopment.Drawing.BorderStyle =
TMGDevelopment.Drawing.BorderStyle.BorderSingle()
' The default CellStyle for the header row
Dim csHeaderDefault As TMGDevelopment.PrintAdapters.CellStyle = New
TMGDevelopment.PrintAdapters.CellStyle(fontHeader, Color.LightGray,
Color.Black, bsGrayBottom)
' A CellStyle with a Wheat background for the table body
row 1
Dim csWheatDefault As TMGDevelopment.PrintAdapters.CellStyle = New
TMGDevelopment.PrintAdapters.CellStyle(fontBody, Color.Wheat, Color.Black,
TMGDevelopment.Drawing.BorderStyle.BorderNone())
' A CellStyle with a OldLace background for the table body
row 2
Dim csOldLaceDefault As TMGDevelopment.PrintAdapters.CellStyle = New
TMGDevelopment.PrintAdapters.CellStyle(fontBody, Color.OldLace, Color.Black,
TMGDevelopment.Drawing.BorderStyle.BorderNone())
' A special CellStyle for the header row
Dim csHeaderLHS As TMGDevelopment.PrintAdapters.CellStyle = New
TMGDevelopment.PrintAdapters.CellStyle("csHeaderLHS", fontHeader,
Color.LightGray, Color.Black, bsGrayBottomRHS)
' A CellStyleMapping to associate the new CellStyle with
the left hand column of the header row
Dim csmHeader As TMGDevelopment.PrintAdapters.CellStyleMapping = New
TMGDevelopment.PrintAdapters.CellStyleMapping(0,
TMGDevelopment.PrintAdapters.ColumnIndexNumbering.FromLeft,
"csHeaderLHS")
' A special CellStyle for the Wheat-colored row
Dim csWheatLHS As TMGDevelopment.PrintAdapters.CellStyle = New
TMGDevelopment.PrintAdapters.CellStyle("csWheatLHS", fontBody,
Color.Wheat, Color.Black, bsGrayRHS)
' A CellStyleMapping to associate the new CellStyle with
the left hand column of the Wheat-colored row
Dim csmWheat As TMGDevelopment.PrintAdapters.CellStyleMapping = New
TMGDevelopment.PrintAdapters.CellStyleMapping(0,
TMGDevelopment.PrintAdapters.ColumnIndexNumbering.FromLeft,
"csWheatLHS")
' A special CellStyle for the OldLace-colored row
Dim csOldLaceLHS As TMGDevelopment.PrintAdapters.CellStyle = New
TMGDevelopment.PrintAdapters.CellStyle("csOldLaceLHS", fontBody,
Color.OldLace, Color.Black, bsGrayRHS)
' A CellStyleMapping to associate the new CellStyle with
the left hand column of the OldLace-colored row
Dim csmOldLace As TMGDevelopment.PrintAdapters.CellStyleMapping = New
TMGDevelopment.PrintAdapters.CellStyleMapping(0,
TMGDevelopment.PrintAdapters.ColumnIndexNumbering.FromLeft,
"csOldLaceLHS")
' RowStyles for the 3 different types of row we're
defining. Note each one takes the default CellStyle
' for the row, and then an array of CellStyles and an array of
CellStyleMappings
Dim rsHeader As TMGDevelopment.PrintAdapters.RowStyle = New
TMGDevelopment.PrintAdapters.RowStyle(csHeaderDefault, Nothing, New
TMGDevelopment.PrintAdapters.CellStyle() {csHeaderLHS}, New
TMGDevelopment.PrintAdapters.CellStyleMapping() {csmHeader})
Dim rsWheatBody As TMGDevelopment.PrintAdapters.RowStyle = New
TMGDevelopment.PrintAdapters.RowStyle(csWheatDefault, Nothing, New
TMGDevelopment.PrintAdapters.CellStyle() {csWheatLHS}, New
TMGDevelopment.PrintAdapters.CellStyleMapping() {csmWheat})
Dim rsOldLaceBody As TMGDevelopment.PrintAdapters.RowStyle = New
TMGDevelopment.PrintAdapters.RowStyle(csOldLaceDefault, Nothing, New
TMGDevelopment.PrintAdapters.CellStyle() {csOldLaceLHS}, New
TMGDevelopment.PrintAdapters.CellStyleMapping() {csmOldLace})
' Finally we construct the TableStyle giving it a name,
and array of RowStyles, no column definitions,
' the outer BorderStyle and setting AutoDetectHeadings and SnapBordersToData
true:
Me.PrintListView2.TableStyle() = New
TMGDevelopment.PrintAdapters.TableStyle("Hard-coded style1", New
TMGDevelopment.PrintAdapters.RowStyle() {rsHeader, rsWheatBody, rsOldLaceBody},
Nothing, bsBlack, True, True)
Me.PrintPreviewDialog2.ShowDialog()
We've shown how complex TableStyles can be built up in the designer, and also how to create the same effect through code. I hope this will give you an idea of the possibilities with the PrintAdapters library, particularly when you combine the style options above with events exposed by PrintListView such as the BeginRow event, which allows you to alter the RowStyle to be used by a given row before it is printed. With this you could adapt the display style to the data (such as showing all sales to a particular customer in a different color, or making the font bold when a value falls below a certain threshold etc). You can even combine the design-time definition of your RowStyles with runtime application of them in a small amount of custom code in the BeginRow event handler.
For more information about PrintAdapters, and other .NET solutions, please visit the WinformReports website at http://www.winformreports.co.uk
July 21, 2003
© 2002-2003 TMG
Development Ltd