Custom WYSIWYG Printing of C1Schedule
C1Schedule includes a printing feature which enables users to get quick printouts of appointments based upon a selected print style and print range. This default printing and previewing uses C1PrintDocument and C1PrintPreviewDialog via reflection, and it uses scripts to design each printing style. The printout styles are designed to be printer-friendly, that is, they are more basic looking than the C1Schedule on the form, i.e. they lack color, and if your schedules are fairly busy, the printouts don't show long or overlapping appointments exactly the same as they appear on screen. The default printing is designed to be very basic and is limited by what scripting is possible in the xml documents. But what if you want a more pixel-perfect printing experience for your users? What if you need to customize the printing beyond just enabling/disabling print option dialogs? This article describes a sample which shows a short-cut approach to printing your C1Schedule exactly "as-is" on your screen. The sample uses the DrawToBitmap method as well as suggestive routines to printing a schedule through this route.
Customized Range Picker
First, we need a date range dialog which allows the user to select which dates to print. It might not always be the same dates they are currently viewing, so users should be able to choose. The PrintRangeDialog includes public StartDate and EndDate members, as well as a GetDateRange method. This method returns a DateTime array representing all the dates between StartDate and EndDate.
public DateTime StartDate
{
get
{
return _startDate;
}
set
{
_startDate = value;
UpdateDates();
dtpkrStart.Value = _startDate;
}
}
public DateTime EndDate
{
get
{
return _endDate;
}
set
{
_endDate = value;
UpdateDates();
dtpkrEnd.Value = _endDate;
}
}
// returns an array representing the date range selected
public DateTime[] GetDateRange()
{
DateTime[] _dateRange = new DateTime[(int)EndDate.ToOADate() - (int)StartDate.ToOADate() 1];
DateTime _start = StartDate;
for (int i = 0; i < _dateRange.Length; i )
{
\_dateRange[i] = \_start;
\_start = \_start.AddDays(1);
}
return _dateRange;
}
Printing C1Schedule
Next, write the code that will prepare the schedule for printing. On the main form put a C1Schedule control (c1Schedule1) and at run-time create a new, in-memory C1Schedule control for printing. By creating a new schedule, this allows us to change the appearance which will be more print-friendly.
private C1Schedule sched = null;
Initiate the printing from either a button or menu.
// create in-memory scheduler control for printing
sched = new C1Schedule();
// copy theme information
sched.Theme.XmlDefinition = c1Schedule1.Theme.XmlDefinition;
// copy time scale information
sched.CalendarInfo.TimeScale = c1Schedule1.CalendarInfo.TimeScale;
// copy view information
sched.ViewType = c1Schedule1.ViewType;
// don't highlight day status for better contrast
sched.Theme.HighlightDayStatus = false;
// It's possible to change other appearance settings for printing version
// To do so:
// - create custom visual style in the smart designer;
// - edit appearance of this visual style;
// - save visual style to file;
// - load saved xml definition into sched.Theme.XmlDefinition property.
sched.Theme.ShowNavigationPanels = false;
// hide title
sched.ShowTitle = false;
// hide free time
sched.ShowWorkTimeOnly = true;
using (MemoryStream stream = new MemoryStream())
{
// copy appointments from the displayed Scheduler
c1Schedule1.DataStorage.Export(stream, FileFormatEnum.XML);
stream.Position = 0;
sched.DataStorage.Import(stream, FileFormatEnum.XML);
}
// set large enough height, so that all day is visible without scrolling
sched.Height = 1200;
// use the same width as in displayed scheduler
sched.Width = c1Schedule1.Width;
// end C1Schedule initialization
((ISupportInitialize)sched).EndInit();
The code above initializes the in-memory schedule by copying certain data from the visible schedule control, including the data. Take this opportunity to change the look of the printed schedule, or keep it looking exactly like the schedule users will see on the form. Next, call the print range dialog and show the desired dates on the print schedule.
// set initial date range
printRangeDialog1.StartDate = c1Schedule1.SelectedDates[0];
if (c1Schedule1.SelectedDates.Length > 1)
{
printRangeDialog1.EndDate = c1Schedule1.SelectedDates[c1Schedule1.SelectedDates.Length - 1];
}
else
{
printRangeDialog1.EndDate = c1Schedule1.SelectedDates[0];
}
// show date range dialog
if (printRangeDialog1.ShowDialog() == DialogResult.OK)
{
// go to desired date
sched.ShowDates(printRangeDialog1.GetDateRange());
// initialize printing
printPreviewDialog1.Document = printDocument1;
printDocument1.PrintPage = new PrintPageEventHandler(printDocument1_PrintPage);
// show print preview
printPreviewDialog1.ShowDialog();
printDocument1.PrintPage -= new PrintPageEventHandler(printDocument1_PrintPage);
}
The code above calls the GetDateRange method from the date range dialog created above. Simply call sched.ShowDates and c1Schedule is smart enough to determine which ViewType best fits the dates. The appointment data will be printed exactly as seen on the screen in the form's schedule. The final bit of code launches a PrintPreviewDialog (although, you could use C1PrintPreviewDialog). Finally, the in-memory C1Schedule is copied as a bitmap to the currently printed page.
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
// copy scheduler to the page
Graphics graphics = e.Graphics;
Rectangle bounds = e.MarginBounds;
Bitmap bitmap = new Bitmap(sched.Width, sched.Height);
sched.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
Rectangle target = new Rectangle(bounds.X, bounds.Y, bounds.Width, bounds.Height);
double xScale = (double)bitmap.Width / bounds.Width;
double yScale = (double)bitmap.Height / bounds.Height;
if (xScale < yScale)
target.Width = (int)(xScale * target.Width / yScale);
else
target.Height = (int)(yScale * target.Height / xScale);
graphics.PageUnit = GraphicsUnit.Display;
graphics.DrawImage(bitmap, target);
}
DrawToBitmap is used to get the image of the in-memory C1Schedule. This code prints the entire schedule to one page.
Conclusion
This sample is intended to be a starting point for creating WYSIWYG printing for C1Schedule. It's not as complete as the built-in printing, but it's completely open to customize how you need. Some code was ommitted from the snippets above, so download the full sample below. Download Sample