The current version of Silverlight, 3.0 doesn’t support any printing features,
but you are however able to print
any content your browser is showing. This doesn’t look very good though…
when printing a full page Silverlight application, the printed document is a compressed
version of the page, the printer squeeze everything into one document.
So i investigated the print size dimensions to be something like 8.5x11 inches ~
612x792 pixels… but was effectively able to print a plugin with the size
of 650x950 pixels nicely.
The Goal
I’ve developed a planning-application called Plan-IT (test/test) where you add tasks to a project..
We and our costumers then wanted a print function, for printing e.g. finished tasks
or assigned tasks or whatever.
The user should be able to click a project node, and thereafter click print to start
printing all the given tasks.
The Technique
The list of actions it takes, to print a series of tasks is as follows:
- 1. Choose project node
- 2. press [print] => opens a popup window
- 3. using a querystring, the application then collects all data and show the corresponding
tasks.
- 4. The VisualRootNode is then replaced by the TaskStack (StackPanel control) to
eliminate all other controls.
- 5. The TaskStack is reducing tasks using tasks.Last(), deleting until the height
of TaskStack is 950px
- 6. The current plugin calls a Javascript method with the list of Tasks that wasn’t
shown.
- 7. if ( list of not shown > 0 ) Goto 4.
- 8. else call “window.print()”
The tricky parts
Figuring out how to fit a SL app onto a sheet of paper took some time. It took some
time to setup the CSS properly and test which pixel size would fit onto the paper
with the given print margin. At first i tried to create one TALL application and
hope that the printer could cut the SL App into pieces like an image, but i was
wrong. Creating multiple instances of 650x950 pixels is the only way to create pages
using Silverligt.
Creating new instances of the SL plugin was a bit tricky. I made this function to
create the next SL Obj:
var SLObjs = 1;
function MakeSLPrinter(strarr) {
var Parent = document.getElementById("SLControls");
var newParent = document.createElement("div")
newParent.setAttribute("id", "silverlightControlHost"
+ SLObjs);
Parent.appendChild(newParent);
var xap = "ClientBin/PlanITSilver.Interface.xap";
var id = "Xaml" + (SLObjs++);
var props = {
width: '650',
height: '950',
inplaceInstallPrompt: false,
background: '#FFFFFF',
isWindowless: 'false',
framerate: '24',
version: '2.0.31005.0'
};
var events = {
onError: onSilverlightError,
onLoad: null,
};
var initParam = QueryString.replace(/&/gi,",") + ", PrintList="
+ strarr;
Silverlight.createObject(xap,newParent,id,props,events,initParam);
}
And the container on the Print.aspx page had to use the new SL3 instantiation…
I’m using the Size_Changed event to reduce the size of the TaskStack like
this:
public List<int> OverFlowTasks = new List<int>();
private void TaskStack_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (EnableSizeLimit && CurrApp.PrintMode)
{
if (TaskStack.ActualHeight > 950)
{
var obj = TaskStack.Children.Last();
if (obj is TaskItem)
{
OverFlowTasks.Add((obj as TaskItem).Task.TaskID);
}
else
{
// Date Header
}
TaskStack.Children.Remove(obj);
}
}
}
The smartest parts
Is of cause that I’m re-using the whole application, instead of creating a
shadow-application. It’s much easier to tweak the original code then to recreate
everything in a clone.