Skip to main content Skip to footer

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   
        return _startDate;  
        _startDate = value;  
        dtpkrStart.Value = _startDate;  
public DateTime EndDate   
        return _endDate;  
        _endDate = value;  
        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  

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];  
    printRangeDialog1.EndDate = c1Schedule1.SelectedDates[0];  

// show date range dialog  
if (printRangeDialog1.ShowDialog() == DialogResult.OK)  
    // go to desired date  

    // initialize printing  
    printPreviewDialog1.Document = printDocument1;  
    printDocument1.PrintPage  = new PrintPageEventHandler(printDocument1_PrintPage);  
    // show print preview  
    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);  
        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.


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

Custom WYSIWYG printing of WPF Scheduler

ComponentOne Product Manager Greg Lutz

Greg Lutz

comments powered by Disqus