Wednesday, January 19, 2011

ArcGIS Silverlight API Printing with Map to Scale

Printing in ArcGIS Silverlight API needs some special coding. To print Map to scale, I have introduced a duplicate Map Control and copying the layers to this control during Print operation.
Here is the working XAML code and the C Sharp code.


XAML code

<UserControl xmlns:esriToolkitPrimitives="clr-namespace:ESRI.ArcGIS.Client.Toolkit.Primitives;assembly=ESRI.ArcGIS.Client.Toolkit"  xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"  x:Class="SL4Print.MainPage"
    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="500" d:DesignWidth="800" xmlns:esri="http://schemas.esri.com/arcgis/client/2009">

    <Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="60"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>

       <esri:Map Background="White" Name="mapControl" Grid.Row="0" Grid.Column="0" ExtentChanged="mapControl_ExtentChanged" Progress="mapControl_Progress" >
            <esri:ArcGISDynamicMapServiceLayer ID="United States" Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" >
            </esri:ArcGISDynamicMapServiceLayer>
  
           
        </esri:Map>
 
        <Button x:Name="InvokePrint" Grid.Row="1" Grid.Column="0" Content="Click Button to Print" Width="200" Height="50"  Click="InvokePrint_Click" />

        <Border x:Name="borderprintMap" BorderThickness="0" BorderBrush="Blue" Width="1056" Height="816" Canvas.ZIndex="-5" Grid.Row="0" >
            <Canvas x:Name="canvasPrint">

                <Border x:Name="borderHeader" Background="SkyBlue">
                    <TextBlock x:Name="headerText" Text="{Binding ElementName=textboxHeader, Path=Text }" TextAlignment="Center" >
                    </TextBlock>
                </Border>
               
                <Canvas>
                   
                    <esri:Map Background="White" Name="mapPrint"   IsLogoVisible="False"  HorizontalAlignment="Center" VerticalAlignment="Center">
                    </esri:Map>
                    <Border x:Name="bordermapPrintScalebar">
                        <esri:ScaleBar Map="{Binding ElementName=mapPrint }"  DisplayUnit="Miles" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
                    </Border>
                </Canvas>
                <Border x:Name="borderFooter" Background="SkyBlue" >
                    <TextBlock x:Name="footerText" Text="{Binding ElementName=textboxFooter, Path=Text}" TextAlignment="Center" HorizontalAlignment="Left">
                    </TextBlock>
                </Border>
           
            </Canvas>
        </Border>
       
        <Border x:Name="borderprintSetup" Width="350" Height="150" Background="LightGray" CornerRadius="20" BorderThickness="2" BorderBrush="Black" Visibility="Collapsed">
            <StackPanel>
            <Grid ShowGridLines="False">
                <Grid.RowDefinitions>
                    <RowDefinition Height="50"></RowDefinition>
                    <RowDefinition Height="50"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100"></ColumnDefinition>
                    <ColumnDefinition Width="250"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <sdk:Label Grid.Row="0" Grid.Column="0" Content="Header Text : " VerticalAlignment="Center" HorizontalAlignment="Right" ></sdk:Label>
                <sdk:Label Grid.Row="1" Grid.Column="0" Content="Footer Text : " VerticalAlignment="Center" HorizontalAlignment="Right" ></sdk:Label>
                    <TextBox x:Name="textboxHeader" Grid.Row="0" Grid.Column="1" Width="200" VerticalAlignment="Center" HorizontalAlignment="Center" Text="Header"/>
                    <TextBox x:Name="textboxFooter" Grid.Row="1" Grid.Column="1" Width="200" VerticalAlignment="Center" HorizontalAlignment="Center" Text="Footer"/>
            </Grid>
                <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" >
                    <Button x:Name="Print" Content="Print"  Width="50" VerticalAlignment="Bottom"  HorizontalAlignment="Left" Margin="10,10,10,10" Click="Print_Click" />
                    <Button x:Name="Cancel" Content="Cancel" Width="50" VerticalAlignment="Bottom"  HorizontalAlignment="Right" Margin="10,10,10,10" Click="Cancel_Click" />
                </StackPanel>
            </StackPanel>
        </Border>
    </Grid>
</UserControl>


C Sharp Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Printing;
using ESRI.ArcGIS.Client;
using System.Windows.Media.Imaging;

namespace SL4Print
{
    public partial class MainPage : UserControl
    {
        bool performPrintSetup = true;

        public MainPage()
        {
            InitializeComponent();
        }

        private void createPrintMapControl()
        {
            mapPrint.Layers.Clear();
            mapPrint.Extent = mapControl.Extent;
            foreach (Layer eachLayer in mapControl.Layers)
            {
                try
                {
                    ArcGISDynamicMapServiceLayer dynamicLayer = eachLayer as ArcGISDynamicMapServiceLayer;
                    if (dynamicLayer != null)
                    {
                        ArcGISDynamicMapServiceLayer newDynamicLayer = new ArcGISDynamicMapServiceLayer();
                        newDynamicLayer.Url = dynamicLayer.Url;
                        newDynamicLayer.Opacity = dynamicLayer.Opacity;
                        dynamicLayer.VisibleLayers = dynamicLayer.VisibleLayers;
                        mapPrint.Layers.Add(newDynamicLayer);
                    }
                    ArcGISTiledMapServiceLayer tiledLayer = eachLayer as ArcGISTiledMapServiceLayer;
                    if (tiledLayer != null)
                    {
                        ArcGISTiledMapServiceLayer newTiledLayer = new ArcGISTiledMapServiceLayer();
                        newTiledLayer.Url = tiledLayer.Url;
                        newTiledLayer.Opacity = tiledLayer.Opacity;
                        mapPrint.Layers.Add(newTiledLayer);
                    }
                    GraphicsLayer graphicsLayer = eachLayer as GraphicsLayer;
                    if (graphicsLayer != null)
                    {
                        GraphicsLayer newGraphicsLayer = new GraphicsLayer();
                        newGraphicsLayer = graphicsLayer;
                    }
                }
                catch(Exception ex)
                {
                    MessageBox.Show("Error when setting up Print Template : " + ex.Message);
                }
            }
        }

        void thePrintDoc_PrintPage(object sender, PrintPageEventArgs e)
        {
            // Header Control
            //borderHeader.Background = new SolidColorBrush(Colors.White);
            borderHeader.BorderThickness = new Thickness(2.0);
            borderHeader.BorderBrush = new SolidColorBrush(Colors.Black);
            borderHeader.SetValue(Canvas.ZIndexProperty, 1);
            borderHeader.SetValue(Canvas.TopProperty, 0.0);
            borderHeader.Width = e.PrintableArea.Width;
            //Map Control
            mapPrint.Width = e.PrintableArea.Width;
            mapPrint.Height = e.PrintableArea.Height;
            // Scalebar Control
            bordermapPrintScalebar.Width = e.PrintableArea.Width;
            bordermapPrintScalebar.SetValue(Canvas.TopProperty, (e.PrintableArea.Height - 35));
            bordermapPrintScalebar.SetValue(Canvas.LeftProperty, 0.0);
            bordermapPrintScalebar.SetValue(Canvas.ZIndexProperty, 1);
            bordermapPrintScalebar.Background = new SolidColorBrush(Colors.Gray);
            // Scale and Footer Control
            //borderFooter.Background = new SolidColorBrush(Colors.White);
            borderFooter.BorderThickness = new Thickness(2.0);
            borderFooter.BorderBrush = new SolidColorBrush(Colors.Black);
            borderFooter.SetValue(Canvas.ZIndexProperty, 1);
            borderFooter.SetValue(Canvas.TopProperty, (e.PrintableArea.Height - 20));
            borderFooter.Width = e.PrintableArea.Width;

            e.PageVisual = canvasPrint;
            e.HasMorePages = false;

        }

        private void mapControl_ExtentChanged(object sender, ExtentEventArgs e)
        {
            mapPrint.Extent = mapControl.Extent;
        }

        private void mapControl_Progress(object sender, ProgressEventArgs e)
        {
            if (e.Progress == 100)
            {
                if (performPrintSetup == true)
                {
                    createPrintMapControl();
                    performPrintSetup = false;
                }
            }
        }

     
        void thePrintDoc_EndPrint(object sender, EndPrintEventArgs e)
        {
            this.Cursor = Cursors.Arrow;
            MessageBox.Show("Printing Completed !");
        }

        void thePrintDoc_BeginPrint(object sender, BeginPrintEventArgs e)
        {
            this.Cursor = Cursors.Wait;
        }

        private void InvokePrint_Click(object sender, RoutedEventArgs e)
        {
            borderprintSetup.Visibility = System.Windows.Visibility.Visible;
        }

        private void Print_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                PrintDocument thePrintDoc = new PrintDocument();
                thePrintDoc.BeginPrint += new EventHandler<BeginPrintEventArgs>(thePrintDoc_BeginPrint);
                thePrintDoc.EndPrint += new EventHandler<EndPrintEventArgs>(thePrintDoc_EndPrint);
                thePrintDoc.PrintPage += new EventHandler<PrintPageEventArgs>(thePrintDoc_PrintPage);
                thePrintDoc.Print("Silverlight 4 Sample Print");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            borderprintSetup.Visibility = System.Windows.Visibility.Collapsed;
        }


        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            borderprintSetup.Visibility = System.Windows.Visibility.Collapsed;
        }


        
    }
}


3 comments:

All Blogs so far ...