Now that we have the page header set up, we're gonna use that user control in our code along with the printing procedure. In my case i have a datagrid with paging, so i want to print all the data and not just the data displayed on the screen. To do that I did a small workaround, basically setting the page size to the Total Item Count before printing and set the size back to its original state. I dont like this work around but works fine for now. This will alllow us to print every row returned by our datagrid. Furthemore, I created another user control that's gonna act as my data container.<UserControl x:Class="DB.Silverlight.Views.ApplicationPrintHeadView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"d:DesignHeight="100" d:DesignWidth="422" Width="1100"><Grid Margin="20,0"><Grid.ColumnDefinitions><ColumnDefinition Width="100" /><ColumnDefinition Width="100" /><ColumnDefinition Width="100" /><ColumnDefinition Width="130" /><ColumnDefinition Width="30" /><ColumnDefinition Width="90" /><ColumnDefinition Width="90" /><ColumnDefinition Width="120" /><ColumnDefinition Width="400" /></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition ></RowDefinition></Grid.RowDefinitions><TextBlock Grid.Column="0" Name="h1" >First Name</TextBlock><TextBlock Grid.Column="1" Name="h2" >Last Name</TextBlock><TextBlock Grid.Column="2" Name="h3">Phone</TextBlock><TextBlock Grid.Column="3" Name="h4">Business Name</TextBlock><TextBlock Grid.Column="4" >Tier</TextBlock><TextBlock Grid.Column="5" >Status</TextBlock><TextBlock Grid.Column="6" >Date Applied</TextBlock><TextBlock Grid.Column="7" >Number Approved</TextBlock><TextBlock Grid.Column="8" >Industry</TextBlock><Border x:Name="TimelineBorder"Background="LightGray"BorderBrush="Black"BorderThickness="1"Margin="0,20,140,0" VerticalAlignment="Top" Grid.ColumnSpan="9"></Border></Grid></UserControl>
ApplicationPrintView is the container that binds all fields of my datagrid(which lives in mainpage.xaml) by assigning the binding property which ties it to the PagedCollectionView. And below is the button click event that fires printing.<UserControl x:Class="DB.Silverlight.Views.ApplicationPrintView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"xmlns:converter="clr-namespace:DB.Silverlight"mc:Ignorable="d"d:DesignHeight="300" d:DesignWidth="422" Width="1100"><UserControl.Resources><converter:ApplicationStatusConverter x:Key="ApplicationStatusConverter" /></UserControl.Resources><Grid Margin="20,0"><StackPanel Name="appData" Orientation="Horizontal"><TextBlock Width="100" Text="{Binding FirstName}" /><TextBlock Width="100" Text="{Binding LastName}" /><TextBlock Width="100" Text="{Binding PhoneNumber}" /><TextBlock Width="130" Text="{Binding BusinessName}" TextWrapping="Wrap" /><TextBlock Width="30" Text="{Binding TierCode}" /><TextBlock Width="90" Text="{Binding applicationStatus,Converter={StaticResource ApplicationStatusConverter}}" /><TextBlock Width="90" Text="{Binding DateApplied}" /><TextBlock Width="100" Text="{Binding NumberApproved}" TextAlignment="Center" /><TextBlock Width="290" Text="{Binding IndustryName}" TextWrapping="Wrap" /></StackPanel></Grid></UserControl>
This will print all data from datagrid across multiple pages with a nicely formatted page header and spaced up page footer so no row gets cut.private void PrintGrid_Click(object sender, RoutedEventArgs e){PrintDocument pd = new PrintDocument();
int ItemIndex = 0;
pd.PrintPage += (s, e) =>{PagedCollectionView items = (PagedCollectionView)dgDashboard.ItemsSource;StackPanel itemHost = new StackPanel();
ApplicationPrintHeadView head = new ApplicationPrintHeadView();
itemHost.Children.Add(head);items.PageSize = items.TotalItemCount;try
{while (ItemIndex < items.TotalItemCount)
{ApplicationPrintView itemsContainer = new ApplicationPrintView();
itemsContainer.appData.DataContext = items[ItemIndex];itemHost.Children.Add(itemsContainer);itemHost.Measure(new Size(e.PrintableArea.Width, double.PositiveInfinity));if (itemHost.DesiredSize.Height > e.PrintableArea.Height && itemHost.Children.Count > 1)
{itemHost.Children.Remove(itemsContainer);e.HasMorePages = true;
break;
}ItemIndex += 1;}}catch (Exception)
{MessageBox.Show("An Unexpected Error Has Occured. Please try again.");
}finally
{items.PageSize = 20;}e.PageVisual = itemHost;};pd.Print("My Document");
}
In summary, this is what i did to set up printing: in my silverlight project I added a folder called Views then added 2 user controls(page header and container) to it. And ofcourse my datagrid lives in mainPage.xaml that's pulling its data thru WCF (I reused the same service used by my ASP.NET application). Another option would be to use Ria Services. I had my silverlight project configured to be hosted in my ASP.NET application, so all i had to do is build the silverlight project to update the xap file.
References: http://channel9.msdn.com/learn/courses/Silverlight4/