ArcGIS API for Silverlight - Library Reference
MapOptions Class
Members  Example  See Also  Send comments on this topic
ESRI.ArcGIS.Client.Printing Namespace : MapOptions Class

Defines map display properties.

Object Model

MapOptions ClassEnvelope ClassSpatialReference ClassTimeExtent Class

Syntax

Visual Basic (Declaration) 
Public Class MapOptions 
C# 
public class MapOptions 

Remarks

WYSIWYG Printing of Maps

The acronym WYSIWYG stands for "What You See Is What You Get" and is typically used to describe what you view on a digital screen (i.e. desktop computer, laptop, tablet, phone, hand held device, etc.) matches a hard copy print output. For a typical application using a 'screen capture' type of WYSIWYG printing, the Microsoft API Printing document serves as a starting point.

For ArcGIS developers who want to produce applications for cartographic map printing, the API's provided by Microsoft may be insufficient. ESRI provides additional resources via the ESRI.ArcGIS.Client.Printing Assembly that suit many of the needs for cartographic map printing via ArcGIS Server.

One common request by ArcGIS developers is the ability to replicate what is seen in the Map Control of an application on a printed map. In a nutshell, the key to producing a WYSIWYG printed output specifically for the Map Control involves

  • Knowing the Data Frame - Knowing the key pieces of information on the ArcGIS Server machine (specifically the Data Frame Height and Data Frame Width of the ArcMap Layout Template).
  • Using a Ratio - Ensuring that the ratio between the Height and Width of the Data Frame in the ArcMap Layout Template exactly matches the ratio between the Height and Width of the Map Control in the application.
  • Ensuring No Scale Dependency Layers - Ensuring that any map Layers in the ArcGIS Service does not use scale dependency visibility rendering (aka. no specific Scale Range was set in ArcMap when authoring the service. Make sure that the Layer is visible for all scale levels).

Note: An example of producing a WYSIWYG printed output specifically for the Map Control using various Layout Template options can be found in the example code section of this document.

ArcGIS Server uses the information provided from the client application to generate the image that is used for printing. There are several options available in the PrintTask.PrintParameters Class which can be used in almost unlimited combinations. The key to making a successful WYSIWYG printed output the Map Control, first involves understanding the constraints that ArcGIS Server has to generate the map image for printing. When a specific Scale and Extent are passed to ArcGIS Server from the client, the image generation process attempts to center the map based upon the Extent and maintain the Scale subject to the Data Frame that is used for a specific Layout Template. In most cases, the size and/or aspect ratio of the of the Map Control on the client does not exactly match the Data Frame on the ArcGIS Server and the result is often seeing more or less geographic coverage in the output image that what is in the Map Control (basically the Scale of the Map Control is different than that of the Data Frame of the Layout Template). Additionally when the Scale that is shown in the Map Control on the client does not match that of the Data Frame in the Layout Template, Layers may or may not draw based upon their scale dependency visibility setting. This may result in an output image that looks very different than what is on the client. How to obtain and use each of the three key pieces of information (listed previously) in order to produce a WYSIWYG printed output specifically for the Map Control will be discussed in more depth as follows:

Knowing the DataFrame

A Layout Template is a map document (.mxd) that is used to define the placement of a map and marginalia for use by ArcGIS Server to generate an output image. The Data Frame is the placeholder for the map (and it's Layers) within the Layout Template. The default location where the Layout Templates are stored on ArcGIS Server is <install_directory>\Templates\ExportWebMapTemplates (see the following screen shot):

Default location of Layout Template map documents on ArcGIS Server.

The filename without the .mxd extension should exactly match the names of the Layout Templates that are listed in Layout_Template parameter of the ArcGIS REST Services Directory under the Choice List option (see the following screen shot):

Finding Layout Template options in the ArcGIS REST Services Directory.

In order to produce a WYSIWYG printed output specifically for the Map Control requires knowing the Data Frame Width and Height in the Layout Template. Using ArcMap, open a particular Layout Template map document (.mxd) and with the Layout View being active, right-click on the Data Frame element and choose Properties... from the context menu (see the following screen shot for opening the ‘Tabloid ANSI B Portrait.mxd’ file):

Opening the 'Tabloid ANSI B Portrait.mxd' file and choosing Properties from the context menu for the Data Frame.

Then click on the Size and Position tab of the Data Frame Properties dialog to obtain the Width and Height arguments (see the following screen shot):

Obtaining the Width and Height settings of the Data Frame.

Using a Ratio

Because the exact aspect ratio of the Map Control on the client and the Data Frame of the Layout Template on ArcGIS Server will typically not match, this will result in scale differences that will give non-WYSIWYG output. To correct for this, it is necessary to create either Height-to-Width ratio or a Width-to-Height ratio using the results of the Height and Width arguments of the Data Frame. This ratio will then be used to adjust either the Height or Width of the Map Control in the client application and thereby ensure that what geographic coverage is in the Map Control exactly matches the Data Frame in the Layout Template. The following provides the generic algorithm for applying the ratio (only one is needed in your application):

            DataFrame.Height = X (<-- some static value)
            DataFrame.Width = Y (<-- some static value)
            MapControl.Height = Z (<-- some static value)
            MapControl.Width = MapControl.Height * (DataFrame.Width / DataFrame.Height)
            
OR
            DataFrame.Height = X (<-- some static value)
            DataFrame.Width = Y (<-- some static value)
            MapControl.Width = Z (<-- some static value)
            MapControl.Height = MapControl.Width * (DataFrame.Height / DataFrame.Width) 
            

Ensuring No Scale Dependency Layers

Because the physical size of the Map Control in the client application and the Data Frame in the Layout Template will most likely not be exactly the same, the Scale will be different. While the Extent of the geographic coverage of the Layers in between the Map Control and the Data Frame may be the same (especially since you made sure the ratio between the two is the same), because the physical size of the two elements is different the Scale will also be inherently different. When Layers (or any sub-Layers) that have scale dependent visibility applied as you zoom in/out, the geographic features that are displayed could change. As a safety precaution to ensure WYSIWYG compliance, it is best that no scale dependency is set on any Layers that are desired to be visible in the Map Control. Examining the ArcGIS REST Services Directory for the Url of the web service for each Layer you can ensure that the Min. Scale and Max. Scale attributes are both zero (0) (see the following screen shot):

Ensuring there are no scale dependency layers using the ArcGIS Rest Services Directory.

If it turns out that non-zero value are present in the web service, it may be necessary to re-author the ArcMap map document (.mxd) and re-publish the web service on ArcGIS Server. Setting the scale dependency visibility in ArcMap is done in the General tab of the Layer Properties dialog; look for the Scale Range section (see the following screen shot):

Setting the 'Show layer at all scales' radio button in the Layer Properties of an authored web service helps ensure WYSIWYG printing.

Example

How to use:

When the application loads, all available Layout Templates that are supported for the PrintTask are listed in the ListBox. Click on a particular Layout Template and the Map Control will appear with the Height and Width of the Control adjusted to match the same ratio as the Data Frame of the Layout Template on the ArcGIS Server machine. This helps to ensure WYSIWYG printing.

The XAML code in this example is used in conjunction with the code-behind (C# or VB.NET) to demonstrate the functionality.

The following screen shot corresponds to the code example in this page.

Creating WYSIWYG prints of the Map Control via the PrintTask.

XAMLCopy Code
<Grid x:Name="LayoutRoot" Background="White">
  <esri:Map Background="White" HorizontalAlignment="Left" Margin="13,288,0,0" Visibility="Collapsed"
            Name="MyMap" VerticalAlignment="Top" WrapAround="True" Height="300" Width="600"
             Extent="-14130480,2889032,-7273626,6317460" BorderBrush="Black" BorderThickness="1">
    <esri:Map.Layers>
      <esri:LayerCollection>
      
        <!-- Add a layer to the Map Control. -->
        <esri:ArcGISDynamicMapServiceLayer ID="MyArcGISDynamicMapServiceLayer"
          Url="http://services.arcgisonline.com/ArcGIS/rest/services/World_Physical_Map/MapServer"/>
        
      </esri:LayerCollection>
    </esri:Map.Layers>
  </esri:Map>
  
  <!-- Url -->
  <sdk:Label Height="20" HorizontalAlignment="Left" Margin="8,100,0,0" Name="Label_Url" 
             VerticalAlignment="Top" Width="31" Content="Url:"/>
  <TextBox Height="23" HorizontalAlignment="Left" Margin="8,118,0,0" Name="TextBox_Url" 
           VerticalAlignment="Top" Width="605" FontSize="10" />
  
  <!-- Button to perform the work. -->
  <Button Content="ExecuteAsync" Height="25" Width="229" HorizontalAlignment="Left" Margin="12,147,0,0" 
          Name="Button_ExecuteAsync" VerticalAlignment="Top" Click="Button_ExecuteAsync_Click" IsEnabled="True"/>
  
  <!-- Provide Width, Height, and their ratio information about the Data Frame and Map Control. -->
  <sdk:Label Height="19" Margin="31,178,483,0" Name="Label_DataFrameHeight" 
             VerticalAlignment="Top" Content="Data Frame Height:" />
  <TextBlock Height="19" HorizontalAlignment="Left" Margin="141,178,0,0" Name="TextBlock_DataFrameHeight" 
             Text="" VerticalAlignment="Top" Width="100" />
  <sdk:Label Height="19" HorizontalAlignment="Left" Margin="36,197,0,0" Name="Label_DataFrameWidth" 
             VerticalAlignment="Top" Width="103" Content="Data Frame Width:"/>
  <TextBlock Height="19" HorizontalAlignment="Left" Margin="141,196,0,0" Name="TextBlock_DataFrameWidth" 
             Text="" VerticalAlignment="Top" Width="100" />
  <sdk:Label Height="19" HorizontalAlignment="Left" Margin="29,216,0,0" Name="Label_MapControlHeight" 
             VerticalAlignment="Top" Width="111" Content="Map Control Height:"/>
  <TextBlock Height="19" HorizontalAlignment="Left" Margin="141,215,0,0" Name="TextBlock_MapControlHeight" 
             Text="" VerticalAlignment="Top" Width="100" />
  <sdk:Label Height="19" HorizontalAlignment="Left" Margin="33,234,0,0" Name="Label_MapControlWidth" 
             VerticalAlignment="Top" Width="109" Content="Map Control Width:"/>
  <TextBlock Height="19" HorizontalAlignment="Left" Margin="141,233,0,0" Name="TextBlock_MapControlWidth" 
             Text="" VerticalAlignment="Top" Width="100" />
  <sdk:Label Height="19" HorizontalAlignment="Left" Margin="13,253,0,0" Name="Label_RatioWidthToHeight" 
             VerticalAlignment="Top" Width="126" Content="Ratio Width To Height:"/>
  <TextBlock Height="19" HorizontalAlignment="Left" Margin="141,251,0,0" Name="TextBlock_RatioWidthToHeight" 
             Text="" VerticalAlignment="Top" Width="100" />
  
  <!-- Display all of the available Layout Template printing options from the PrintTask web service. -->
  <sdk:Label Height="19" HorizontalAlignment="Left" Margin="288,144,0,0" Name="Label_LayoutTemplate" 
             VerticalAlignment="Top" Width="98" Content="Layout Tempate:" />
  <ListBox Height="110" HorizontalAlignment="Left" Margin="288,160,0,0" Name="ListBox_LayoutTemplate" 
            VerticalAlignment="Top" Width="226" SelectionChanged="ListBox_LayoutTemplate_SelectionChanged"/>
  
  <!-- Provide the instructions on how to use the sample code. -->
  <TextBlock Height="94" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="625" 
     TextWrapping="Wrap" Text="When the application loads, all available Layout Templates that are supported 
     for the PrintTask are listed in the ListBox. Click on a particular Layout Template and the Map Control 
     will appear with the Height and Width of the Control adjusted to match the same ratio as the Data Frame 
     of the Layout Template on the ArcGIS Server machine. This helps to ensure WYSIWYG printing." />
  
</Grid>
C#Copy Code
// Create Global (aka. Member) variables for the PrintTask and a Dictionary objects that will be 
// used in other parts of the application.
public ESRI.ArcGIS.Client.Printing.PrintTask _PrintTask;
public Dictionary<string, DataFrameAndMapControlInfo> _StaticDataFrameAndMapControlInfo = new Dictionary<string, DataFrameAndMapControlInfo>();
  
// Create a custom Class that will hold information necessary to facilitate WYSIWYG printing of the
// client application Map Control using a Layout Template on ArcGIS Server. Information about the 
// Width and Height of the Data Frame of the Layout Templates on the ArcGIS Server Machine is stored.
// A ratio of Width to Height is stored. Also the size (Width and Height) of the Map Contol is stored. 
public class DataFrameAndMapControlInfo
{
  public string Name;
  public double DataFrame_Width;
  public double DataFrame_Height;
  public double Ratio_WidthToHeight;
  public double MapControl_Width;
  public double MapControl_Height;
}
            
public MainPage()
{
  InitializeComponent();
  
  // Provide a valid PrintTask.Url for a "synchronous geoprocessing task"
  TextBox_Url.Text = "http://localhost:6080/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export20Web20Map%20Task";
  
  // Set the _PrintTask variable to a new instance of the PrintTask Class.
  _PrintTask = new ESRI.ArcGIS.Client.Printing.PrintTask();
  
  // Prevent the internet browser from using a cache for the PrintTask operations.
  _PrintTask.DisableClientCaching = true;
  
  // Set the PrintTask.Url from what is entered in the TextBox.
  _PrintTask.Url = TextBox_Url.Text;
  
  // Wire up an Event Handler for the PrintTask.GetServiceInfoCompleted Event.
  _PrintTask.GetServiceInfoCompleted += printTask_GetServiceInfoCompleted;
  
  // Call the PrintTask.GetServiceInfoAsync Method which will give information about the PrintTask
  // web service (via the PrintServiceInfo Class). Especially useful to find what Layout Templates
  // are supported in the web service.
  _PrintTask.GetServiceInfoAsync();
  
  // Wire up an Event Handler for the PrintTask.ExecuteCompleted Event.
  _PrintTask.ExecuteCompleted += printTask_ExecuteCompleted;
  
  // Call a custom function to store all of the hard coded values about the Data Frame element in 
  // the Layout Template as well as information about the Map Control in the client application.
  PopulateStaticDataFrameInfo();
}
            
private void printTask_GetServiceInfoCompleted(object sender, ESRI.ArcGIS.Client.Printing.ServiceInfoEventArgs e)
{
  // Gets information about the PrintTask web service.
  
  // Get the PrintServiceInfo object.
  ESRI.ArcGIS.Client.Printing.PrintServiceInfo myPrintServiceInfo = e.ServiceInfo;
  
  // Get the IEnumerable of the Layout Template names available on the PrintTask web service.
  IEnumerable<string> myLayoutTemplates = myPrintServiceInfo.LayoutTemplates;
  
  // Loop through all of the names of the Layout Templates and add them to the ListBox.
  foreach (string myLayoutTemplate in myLayoutTemplates)
  {
    ListBox_LayoutTemplate.Items.Add(myLayoutTemplate);
  }
}
            
public void PopulateStaticDataFrameInfo()
{
  // This is a custom function to store all of the hard coded values about the Data Frame element in 
  // the Layout Template as well as information about the Map Control in the client application.
  //
  // The DataFrameAndMapControlInfo.DataFrame_Height and DataFrameAndMapControlInfo.DataFrame_Width 
  // hardcoded variables were obtained by opening the Layout Template map document (.mxd) file on 
  // the ArcGIS Server machine. The default location where the Layout Templates are stored on ArcGIS 
  // Server is <nstall_directory>\Templates\ExportWebMapTemplates. The filename of the Layout Template
  // map document (without the .mxd extension) should match the names of the Layout Templates returned
  // from the PrintTask.GetServiceInfoCompleted Event.
  //
  // The DataFrameAndMapControlInfo.Ratio_WidthToHeight variables are calcualted to figure out the
  // ratio of the Width to Height of the Data Frame. This will then be used to calculate the Width
  // of the Map Control on the client application such that the ratio of Height to Width in the Data 
  // Frame matches the ratio of Height to Width in the Map Control. This is the key to getting a
  // WYSIWYG printing of the Map Control in the output returned from the PrintTask.
  
  DataFrameAndMapControlInfo x = new DataFrameAndMapControlInfo();
  x.Name = "MAP_ONLY";
  x.DataFrame_Height = 4.167;
  x.DataFrame_Width = 4.167;
  x.Ratio_WidthToHeight = x.DataFrame_Width / x.DataFrame_Height;
  x.MapControl_Height = 400;
  x.MapControl_Width = x.MapControl_Height * x.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x.Name, x);
  
  DataFrameAndMapControlInfo x1 = new DataFrameAndMapControlInfo();
  x1.Name = "A3 Landscape";
  x1.DataFrame_Height = 21.1688;
  x1.DataFrame_Width = 39.9998;
  x1.Ratio_WidthToHeight = x1.DataFrame_Width / x1.DataFrame_Height;
  x1.MapControl_Height = 400;
  x1.MapControl_Width = x1.MapControl_Height * x1.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x1.Name, x1);
  
  DataFrameAndMapControlInfo x2 = new DataFrameAndMapControlInfo();
  x2.Name = "A3 Portrait";
  x2.DataFrame_Height = 29.0002;
  x2.DataFrame_Width = 27.6756;
  x2.Ratio_WidthToHeight = x2.DataFrame_Width / x2.DataFrame_Height;
  x2.MapControl_Height = 400;
  x2.MapControl_Width = x2.MapControl_Height * x2.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x2.Name, x2);
  
  DataFrameAndMapControlInfo x3 = new DataFrameAndMapControlInfo();
  x3.Name = "A4 Landscape";
  x3.DataFrame_Height = 15.918;
  x3.DataFrame_Width = 27.7564;
  x3.Ratio_WidthToHeight = x3.DataFrame_Width / x3.DataFrame_Height;
  x3.MapControl_Height = 400;
  x3.MapControl_Width = x3.MapControl_Height * x3.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x3.Name, x3);
  
  DataFrameAndMapControlInfo x4 = new DataFrameAndMapControlInfo();
  x4.Name = "A4 Portrait";
  x4.DataFrame_Height = 22.285;
  x4.DataFrame_Width = 19.024;
  x4.Ratio_WidthToHeight = x4.DataFrame_Width / x4.DataFrame_Height;
  x4.MapControl_Height = 400;
  x4.MapControl_Width = x4.MapControl_Height * x4.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x4.Name, x4);
  
  DataFrameAndMapControlInfo x5 = new DataFrameAndMapControlInfo();
  x5.Name = "Letter ANSI A Landscape";
  x5.DataFrame_Height = 6.25;
  x5.DataFrame_Width = 10;
  x5.Ratio_WidthToHeight = x5.DataFrame_Width / x5.DataFrame_Height;
  x5.MapControl_Height = 400;
  x5.MapControl_Width = x5.MapControl_Height * x5.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x5.Name, x5);
  
  DataFrameAndMapControlInfo x6 = new DataFrameAndMapControlInfo();
  x6.Name = "Letter ANSI A Portrait";
  x6.DataFrame_Height = 8;
  x6.DataFrame_Width = 7.5;
  x6.Ratio_WidthToHeight = x6.DataFrame_Width / x6.DataFrame_Height;
  x6.MapControl_Height = 400;
  x6.MapControl_Width = x6.MapControl_Height * x6.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x6.Name, x6);
  
  DataFrameAndMapControlInfo x7 = new DataFrameAndMapControlInfo();
  x7.Name = "Tabloid ANSI B Landscape";
  x7.DataFrame_Height = 7.7571;
  x7.DataFrame_Width = 16;
  x7.Ratio_WidthToHeight = x7.DataFrame_Width / x7.DataFrame_Height;
  x7.MapControl_Height = 400;
  x7.MapControl_Width = x7.MapControl_Height * x7.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x7.Name, x7);
  
  DataFrameAndMapControlInfo x8 = new DataFrameAndMapControlInfo();
  x8.Name = "Tabloid ANSI B Portrait";
  x8.DataFrame_Height = 11.75;
  x8.DataFrame_Width = 10;
  x8.Ratio_WidthToHeight = x8.DataFrame_Width / x8.DataFrame_Height;
  x8.MapControl_Height = 400;
  x8.MapControl_Width = x8.MapControl_Height * x8.Ratio_WidthToHeight;
  _StaticDataFrameAndMapControlInfo.Add(x8.Name, x8);
}
            
private void ListBox_LayoutTemplate_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
  // The user clicked on a Layout Template name in the ListBox.
  
  // Make the Map Control visible.
  MyMap.Visibility = Windows.Visibility.Visible;
  
  // Get the user selected Layout Template name.
  string theChoice = ListBox_LayoutTemplate.SelectedItem;
  
  // Find the correct DataFrameAndMapControlInfo object which contains static information about
  // the Data Frame and Map Control.
  DataFrameAndMapControlInfo oneDataFrameInfo = _StaticDataFrameAndMapControlInfo[theChoice];
  
  // Adjust the Height and Width of the Map Control to match the same ratio as the Data Frame in the
  // Layout Template.
  MyMap.Height = oneDataFrameInfo.MapControl_Height;
  MyMap.Width = oneDataFrameInfo.MapControl_Width;
  
  // Display the static information in the DataFrameAndMapControlInfo to the user.
  TextBlock_DataFrameHeight.Text = oneDataFrameInfo.DataFrame_Height.ToString();
  TextBlock_DataFrameWidth.Text = oneDataFrameInfo.DataFrame_Width.ToString();
  TextBlock_MapControlHeight.Text = oneDataFrameInfo.MapControl_Height.ToString();
  TextBlock_MapControlWidth.Text = oneDataFrameInfo.MapControl_Width.ToString();
  TextBlock_RatioWidthToHeight.Text = oneDataFrameInfo.Ratio_WidthToHeight.ToString();
}
            
private void Button_ExecuteAsync_Click(object sender, System.Windows.RoutedEventArgs e)
{
  // The user clicked the button to generate an output map image.
  
  // Get the user selected Layout Template name.
  string theChoice = ListBox_LayoutTemplate.SelectedItem;
  
  // Find the correct DataFrameAndMapControlInfo object which contains static information about
  // the Data Frame and Map Control.
  DataFrameAndMapControlInfo oneDataFrameInfo = _StaticDataFrameAndMapControlInfo[theChoice];
  
  // Define the settings for rendering the image/.pdf on the ArcGIS Server.
  
  // Define the PrintParameters.
  ESRI.ArcGIS.Client.Printing.PrintParameters myPrintParameters = new ESRI.ArcGIS.Client.Printing.PrintParameters(MyMap);
  myPrintParameters.LayoutTemplate = oneDataFrameInfo.Name;
  myPrintParameters.Format = "JPG"; // Look to the REST service to see what image formats are supported.
  
  // Define the MapOptions. It is imperative that this Class be used but only the Map.Extent be provided
  // (either via the constructor or via the Property). Do not set the MapOptions.Scale Property! We want 
  // the PrintTask on ArcGIS Server to maintain the same Extent between the Map Control and the Data Frame
  // in the Layout Template, the Scale on ArcGIS server will be adjusted according to the Extent and the
  // size of the Data Frame in the Layout Template.
  ESRI.ArcGIS.Client.Printing.MapOptions myMapOptions = new ESRI.ArcGIS.Client.Printing.MapOptions(MyMap.Extent);
  myPrintParameters.MapOptions = myMapOptions;
  
  // NOTE: 
  // If you try to submit more that one 'synchronous geoprocessing task' via PrintTask.ExecuteAsync at a time 
  // using the ExecuteAsync methadology you will get a Visual Studio (Runtime) error: 
  // NotSupportedException was unhandled by user code. "Task does not support concurrent  I/O operations. Cancel 
  // the pending request or wait for it to complete." 
  // In order to overcome this, use the PrintTask.IsBusy Property and take action accordingly.
  
  if (_PrintTask.IsBusy == true)
  {
    // There is an existing 'synchronous geoprocessing task' PrintTask running. 
    // Wait a few moments for the output to be generated and click the button again.
  }
  else if (_PrintTask.IsBusy == false)
  {
    // There is not an existing 'synchronous geoprocessing task' PrintTask running.
     
    // Use the 'synchronous geoprocessing task' PrintTask.ExecuteAsync Method.
    _PrintTask.ExecuteAsync(myPrintParameters);
  }
}
            
private void printTask_ExecuteCompleted(object sender, ESRI.ArcGIS.Client.Printing.PrintEventArgs e)
{
  // Use only for ExecuteAsync operations (i.e. synchronous geoprocessing tasks).
  
  // Get any error information (add your own enhancements if desired). 
  System.Exception mySystemException = e.Error;
  
  // Get the PrintResult from the completed operation.
  ESRI.ArcGIS.Client.Printing.PrintResult myPrintResult = e.PrintResult;
  
  // Test is we have valid return PrintResults.
  if (myPrintResult != null)
  {
    // Get any messages returned from ArcGIS Server (add your own enhancements if desired).
    List<ESRI.ArcGIS.Client.Tasks.GPMessage> myListOfGPMessage = myPrintResult.Messages;
    
    // Get the location of the image/.pdf created by ArcGIS Server.
    System.Uri myUri = myPrintResult.Url;
    
    // Open a new internet browser window with the generated image from the PrintTask.
    System.Windows.Browser.HtmlPage.Window.Navigate(myUri, "_blank");
  }
}
VB.NETCopy Code
' Create Global (aka. Member) variables for the PrintTask and a Dictionary objects that will be 
' used in other parts of the application.
Public _PrintTask As ESRI.ArcGIS.Client.Printing.PrintTask
Public _StaticDataFrameAndMapControlInfo As New Dictionary(Of String, DataFrameAndMapControlInfo)
            
' Create a custom Class that will hold information necessary to facilitate WYSIWYG printing of the
' client application Map Control using a Layout Template on ArcGIS Server. Information about the 
' Width and Height of the Data Frame of the Layout Templates on the ArcGIS Server Machine is stored.
' A ratio of Width to Height is stored. Also the size (Width and Height) of the Map Contol is stored. 
Public Class DataFrameAndMapControlInfo
  Public Name As String
  Public DataFrame_Width As Double
  Public DataFrame_Height As Double
  Public Ratio_WidthToHeight As Double
  Public MapControl_Width As Double
  Public MapControl_Height As Double
End Class
            
Public Sub New()
  
  InitializeComponent()
   
  ' Provide a valid PrintTask.Url for a "synchronous geoprocessing task"
  TextBox_Url.Text = "http://localhost:6080/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export20Web20Map%20Task"
  
  ' Set the _PrintTask variable to a new instance of the PrintTask Class.
   _PrintTask = New ESRI.ArcGIS.Client.Printing.PrintTask()
  
  ' Prevent the internet browser from using a cache for the PrintTask operations.
  _PrintTask.DisableClientCaching = True
  
  ' Set the PrintTask.Url from what is entered in the TextBox.
  _PrintTask.Url = TextBox_Url.Text
  
  ' Wire up an Event Handler for the PrintTask.GetServiceInfoCompleted Event.
  AddHandler _PrintTask.GetServiceInfoCompleted, AddressOf printTask_GetServiceInfoCompleted
  
  ' Call the PrintTask.GetServiceInfoAsync Method which will give information about the PrintTask
  ' web service (via the PrintServiceInfo Class). Especially useful to find what Layout Templates
  ' are supported in the web service.
  _PrintTask.GetServiceInfoAsync()
  
  ' Wire up an Event Handler for the PrintTask.ExecuteCompleted Event.
  AddHandler _PrintTask.ExecuteCompleted, AddressOf printTask_ExecuteCompleted
  
  ' Call a custom function to store all of the hard coded values about the Data Frame element in 
  ' the Layout Template as well as information about the Map Control in the client application.
  PopulateStaticDataFrameInfo()
  
End Sub
  
Private Sub printTask_GetServiceInfoCompleted(sender As Object, e As ESRI.ArcGIS.Client.Printing.ServiceInfoEventArgs)
  
  ' Gets information about the PrintTask web service.
  
  ' Get the PrintServiceInfo object.
  Dim myPrintServiceInfo As ESRI.ArcGIS.Client.Printing.PrintServiceInfo = e.ServiceInfo
  
  ' Get the IEnumerable of the Layout Template names available on the PrintTask web service.
  Dim myLayoutTemplates As IEnumerable(Of String) = myPrintServiceInfo.LayoutTemplates
  
  ' Loop through all of the names of the Layout Templates and add them to the ListBox.
  For Each myLayoutTemplate As String In myLayoutTemplates
    ListBox_LayoutTemplate.Items.Add(myLayoutTemplate)
  Next
  
End Sub
            
Public Sub PopulateStaticDataFrameInfo()
  
  ' This is a custom function to store all of the hard coded values about the Data Frame element in 
  ' the Layout Template as well as information about the Map Control in the client application.
  '
  ' The DataFrameAndMapControlInfo.DataFrame_Height and DataFrameAndMapControlInfo.DataFrame_Width 
  ' hardcoded variables were obtained by opening the Layout Template map document (.mxd) file on 
  ' the ArcGIS Server machine. The default location where the Layout Templates are stored on ArcGIS 
  ' Server is <install_directory>\Templates\ExportWebMapTemplates. The filename of the Layout Template
  ' map document (without the .mxd extension) should match the names of the Layout Templates returned
  ' from the PrintTask.GetServiceInfoCompleted Event.
  '
  ' The DataFrameAndMapControlInfo.Ratio_WidthToHeight variables are calcualted to figure out the
  ' ratio of the Width to Height of the Data Frame. This will then be used to calculate the Width
  ' of the Map Control on the client application such that the ratio of Height to Width in the Data 
  ' Frame matches the ratio of Height to Width in the Map Control. This is the key to getting a
  ' WYSIWYG printing of the Map Control in the output returned from the PrintTask.
  
  Dim x As New DataFrameAndMapControlInfo
  x.Name = "MAP_ONLY"
  x.DataFrame_Height = 4.167
  x.DataFrame_Width = 4.167
  x.Ratio_WidthToHeight = x.DataFrame_Width / x.DataFrame_Height
  x.MapControl_Height = 400
  x.MapControl_Width = x.MapControl_Height * x.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x.Name, x)
  
  Dim x1 As New DataFrameAndMapControlInfo
  x1.Name = "A3 Landscape"
  x1.DataFrame_Height = 21.1688
  x1.DataFrame_Width = 39.9998
  x1.Ratio_WidthToHeight = x1.DataFrame_Width / x1.DataFrame_Height
  x1.MapControl_Height = 400
  x1.MapControl_Width = x1.MapControl_Height * x1.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x1.Name, x1)
  
  Dim x2 As New DataFrameAndMapControlInfo
  x2.Name = "A3 Portrait"
  x2.DataFrame_Height = 29.0002
  x2.DataFrame_Width = 27.6756
  x2.Ratio_WidthToHeight = x2.DataFrame_Width / x2.DataFrame_Height
  x2.MapControl_Height = 400
  x2.MapControl_Width = x2.MapControl_Height * x2.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x2.Name, x2)
  
  Dim x3 As New DataFrameAndMapControlInfo
  x3.Name = "A4 Landscape"
  x3.DataFrame_Height = 15.918
  x3.DataFrame_Width = 27.7564
  x3.Ratio_WidthToHeight = x3.DataFrame_Width / x3.DataFrame_Height
  x3.MapControl_Height = 400
  x3.MapControl_Width = x3.MapControl_Height * x3.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x3.Name, x3)
  
  Dim x4 As New DataFrameAndMapControlInfo
  x4.Name = "A4 Portrait"
  x4.DataFrame_Height = 22.285
  x4.DataFrame_Width = 19.024
  x4.Ratio_WidthToHeight = x4.DataFrame_Width / x4.DataFrame_Height
  x4.MapControl_Height = 400
  x4.MapControl_Width = x4.MapControl_Height * x4.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x4.Name, x4)
  
  Dim x5 As New DataFrameAndMapControlInfo
  x5.Name = "Letter ANSI A Landscape"
  x5.DataFrame_Height = 6.25
  x5.DataFrame_Width = 10
  x5.Ratio_WidthToHeight = x5.DataFrame_Width / x5.DataFrame_Height
  x5.MapControl_Height = 400
  x5.MapControl_Width = x5.MapControl_Height * x5.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x5.Name, x5)
  
  Dim x6 As New DataFrameAndMapControlInfo
  x6.Name = "Letter ANSI A Portrait"
  x6.DataFrame_Height = 8
  x6.DataFrame_Width = 7.5
  x6.Ratio_WidthToHeight = x6.DataFrame_Width / x6.DataFrame_Height
  x6.MapControl_Height = 400
  x6.MapControl_Width = x6.MapControl_Height * x6.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x6.Name, x6)
  
  Dim x7 As New DataFrameAndMapControlInfo
  x7.Name = "Tabloid ANSI B Landscape"
  x7.DataFrame_Height = 7.7571
  x7.DataFrame_Width = 16
  x7.Ratio_WidthToHeight = x7.DataFrame_Width / x7.DataFrame_Height
  x7.MapControl_Height = 400
  x7.MapControl_Width = x7.MapControl_Height * x7.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x7.Name, x7)
  
  Dim x8 As New DataFrameAndMapControlInfo
  x8.Name = "Tabloid ANSI B Portrait"
  x8.DataFrame_Height = 11.75
  x8.DataFrame_Width = 10
  x8.Ratio_WidthToHeight = x8.DataFrame_Width / x8.DataFrame_Height
  x8.MapControl_Height = 400
  x8.MapControl_Width = x8.MapControl_Height * x8.Ratio_WidthToHeight
  _StaticDataFrameAndMapControlInfo.Add(x8.Name, x8)
  
End Sub
            
Private Sub ListBox_LayoutTemplate_SelectionChanged(sender As System.Object, e As System.Windows.Controls.SelectionChangedEventArgs)
  
  ' The user clicked on a Layout Template name in the ListBox.
  
  ' Make the Map Control visible.
  MyMap.Visibility = Windows.Visibility.Visible
  
  ' Get the user selected Layout Template name.
  Dim theChoice As String = ListBox_LayoutTemplate.SelectedItem
  
  ' Find the correct DataFrameAndMapControlInfo object which contains static information about
  ' the Data Frame and Map Control.
  Dim oneDataFrameInfo As DataFrameAndMapControlInfo = _StaticDataFrameAndMapControlInfo.Item(theChoice)
  
  ' Adjust the Height and Width of the Map Control to match the same ratio as the Data Frame in the
  ' Layout Template.
  MyMap.Height = oneDataFrameInfo.MapControl_Height
  MyMap.Width = oneDataFrameInfo.MapControl_Width
  
  ' Display the static information in the DataFrameAndMapControlInfo to the user.
  TextBlock_DataFrameHeight.Text = oneDataFrameInfo.DataFrame_Height.ToString
  TextBlock_DataFrameWidth.Text = oneDataFrameInfo.DataFrame_Width.ToString
  TextBlock_MapControlHeight.Text = oneDataFrameInfo.MapControl_Height.ToString
  TextBlock_MapControlWidth.Text = oneDataFrameInfo.MapControl_Width.ToString
  TextBlock_RatioWidthToHeight.Text = oneDataFrameInfo.Ratio_WidthToHeight.ToString
  
End Sub
  
Private Sub Button_ExecuteAsync_Click(sender As System.Object, e As System.Windows.RoutedEventArgs)
  
  ' The user clicked the button to generate an output map image.
  
  ' Get the user selected Layout Template name.
  Dim theChoice As String = ListBox_LayoutTemplate.SelectedItem
  
  ' Find the correct DataFrameAndMapControlInfo object which contains static information about
  ' the Data Frame and Map Control.
  Dim oneDataFrameInfo As DataFrameAndMapControlInfo = _StaticDataFrameAndMapControlInfo.Item(theChoice)
  
  ' Define the settings for rendering the image/.pdf on the ArcGIS Server.
  
  ' Define the PrintParameters.
  Dim myPrintParameters As New ESRI.ArcGIS.Client.Printing.PrintParameters(MyMap)
  myPrintParameters.LayoutTemplate = oneDataFrameInfo.Name
  myPrintParameters.Format = "JPG" ' Look to the REST service to see what image formats are supported.
  
  ' Define the MapOptions. It is imperative that this Class be used but only the Map.Extent be provided
  ' (either via the constructor or via the Property). Do not set the MapOptions.Scale Property! We want 
  ' the PrintTask on ArcGIS Server to maintain the same Extent between the Map Control and the Data Frame
  ' in the Layout Template, the Scale on ArcGIS server will be adjusted according to the Extent and the
  ' size of the Data Frame in the Layout Template.
  Dim myMapOptions As New ESRI.ArcGIS.Client.Printing.MapOptions(MyMap.Extent)
  myPrintParameters.MapOptions = myMapOptions
  
  ' NOTE: 
  ' If you try to submit more that one 'synchronous geoprocessing task' via PrintTask.ExecuteAsync at a time 
  ' using the ExecuteAsync methadology you will get a Visual Studio (Runtime) error: 
  ' NotSupportedException was unhandled by user code. "Task does not support concurrent  I/O operations. Cancel 
  ' the pending request or wait for it to complete." 
  ' In order to overcome this, use the PrintTask.IsBusy Property and take action accordingly.
  
  If _PrintTask.IsBusy = True Then
    
    ' There is an existing 'synchronous geoprocessing task' PrintTask running. 
    ' Wait a few moments for the output to be generated and click the button again.
    
  ElseIf _PrintTask.IsBusy = False Then
    
    ' There is not an existing 'synchronous geoprocessing task' PrintTask running.
    
    ' Use the 'synchronous geoprocessing task' PrintTask.ExecuteAsync Method.
    _PrintTask.ExecuteAsync(myPrintParameters)
    
  End If
  
End Sub
            
Private Sub printTask_ExecuteCompleted(sender As Object, e As ESRI.ArcGIS.Client.Printing.PrintEventArgs)
  
  ' Use only for ExecuteAsync operations (i.e. synchronous geoprocessing tasks).
  
  ' Get any error information (add your own enhancements if desired). 
  Dim mySystemException As System.Exception = e.Error
  
  ' Get the PrintResult from the completed operation.
  Dim myPrintResult As ESRI.ArcGIS.Client.Printing.PrintResult = e.PrintResult
  
  ' Test is we have valid return PrintResults.
  If myPrintResult IsNot Nothing Then
    
    ' Get any messages returned from ArcGIS Server (add your own enhancements if desired).
    Dim myListOfGPMessage As List(Of ESRI.ArcGIS.Client.Tasks.GPMessage) = myPrintResult.Messages
    
    ' Get the location of the image/.pdf created by ArcGIS Server.
    Dim myUri As System.Uri = myPrintResult.Url
    
    ' Open a new internet browser window with the generated image from the PrintTask.
    System.Windows.Browser.HtmlPage.Window.Navigate(myUri, "_blank")
    
  End If
  
End Sub

Inheritance Hierarchy

System.Object
   ESRI.ArcGIS.Client.Printing.MapOptions

Requirements

Target Platforms: Windows XP Professional, Windows Server 2003 family, Windows Vista, Windows Server 2008 family, Windows 7

See Also

© ESRI, Inc. All Rights Reserved.