Visual Basic (Declaration) | |
---|---|
Public Class MapOptions |
C# | |
---|---|
public class MapOptions |
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 Overview 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):
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):
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):
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):
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):
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):
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.
XAML | Copy 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.NET | 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 _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 |
System.Object
ESRI.ArcGIS.Client.Printing.MapOptions
Target Platforms: Windows XP Professional, Windows Server 2003 family, Windows Vista, Windows Server 2008 family, Windows 7, Windows 8