Select to view content in your preferred language

Trouble printing graphics layer with Silverlight 4

2496
6
08-26-2010 08:08 AM
LisaChesley
Emerging Contributor
Good morning, all!

So far, printing from Silverlight 4 works wonderfully for base and dynamic layers, but not so wonderfully for graphic layers.

If you have graphic layers, you can import them onto a print preview map, and print the map successfully, but if you then try to add another graphic to the graphics layer on your original map, you get the error described here (near the bottom of the thread):

http://forums.arcgis.com/threads/8269-Is-there-any-print-example-that-can-be-referenced-for-SL-4

Please find a sample project attached.  To duplicate the error, select a state from the combo box, print (either print or cancel, doesn't matter which), then choose another state from the combo box, and you will get the error.

This project was created with Visual Studio 2010, Silverlight 4, Silverlight API v2.0, and ArcGIS server 10.

Thanks!

Lisa Chesley
0 Kudos
6 Replies
ChrisSmith
Emerging Contributor
Hi

I think it is because you are copying your graphics, but really you are just taking a reference to them and so both layers are pointing to the same collection of graphics/geometries.

It looks like you need to do a deep clone of your graphics collection - or at least the geometries as I dont think they are allowed to exist in multiple GraphicsLayers

Replace the following code...
in class MapPrintViewViewModel
replace CreateGraphicsLayer with this method...

 public GraphicsLayer CreateGraphicsLayer()
        {
            GraphicsLayer graphicsLayer = new GraphicsLayer();
            foreach (Graphic g in MapGraphics)
            {
                graphicsLayer.Graphics.Add(g);
            }
            //graphicsLayer.Graphics = MapGraphics as GraphicCollection;

            return graphicsLayer;
        }



in mainpage.xaml.cs replace the btnPrint_Click method with the code below...

private void btnPrint_Click(object sender, RoutedEventArgs e)
        {
            //Initialize the view model for the map print.
            MapPrintViewViewModel viewModel = new MapPrintViewViewModel();

            //Get the current base map.
            ArcGISTiledMapServiceLayer layer = MyMap.Layers[0] as ArcGISTiledMapServiceLayer;
            viewModel.BaseMapURL = layer.Url;

            //Get the current map extent.
            viewModel.CurrentExtent = MyMap.Extent;

            //Get a collection of visible dynamic layers.            

            foreach (Layer dLayer in MyMap.Layers)
            {
                try
                {
                    if (dLayer is ArcGISDynamicMapServiceLayer)
                    {
                        ArcGISDynamicMapServiceLayer dynamicLayer = dLayer as ArcGISDynamicMapServiceLayer;
                        //If the dynamic layer is currently visible, add it to the print map.

                        //if (dynamicLayer.VisibleLayers != null)
                        if (dynamicLayer.VisibleLayers.Count() > 0)
                        {
                            //dynamicLayers.Add(dynamicLayer);
                            viewModel.VisibleLayers.Add(new MapPrintViewViewModel.DynamicMapLayerInformation(dynamicLayer.MapName, dynamicLayer.Url, dynamicLayer.Opacity, dynamicLayer.VisibleLayers));
                        }
                    }
                }
                catch { }

                try
                {
                    if (dLayer is GraphicsLayer)
                    {
                        GraphicsLayer graphicsLayer = dLayer as GraphicsLayer;
                        //viewModel.MapGraphics = graphicsLayer.Graphics;
                        foreach (Graphic g in graphicsLayer.Graphics)
                        {
                            Graphic clonedGraphic = new Graphic();
                            clonedGraphic.Geometry = ((ESRI.ArcGIS.Client.Geometry.Polygon)g.Geometry).Clone();
                            foreach (KeyValuePair<string, object> o in g.Attributes)
                            {
                                clonedGraphic.Attributes.Add(o.Key, o.Value);
                            }
                            clonedGraphic.Symbol = g.Symbol;
                            viewModel.MapGraphics.Add(clonedGraphic);
                        }
                    }
                }
                catch { }
            }

            MapPrintView printView = new MapPrintView();
            printView.DataContext = viewModel;
            printView.BuildMap();

            //If there are layers to build a legend for, build the legend.
            if (viewModel.VisibleLayers != null && viewModel.VisibleLayers.Count > 0)
            {
                printView.CreateLegend();
            }

            printView.Show();        
        }


hope this helps

regards

chris
0 Kudos
LisaChesley
Emerging Contributor
Good morning, Chris!

That did the trick!  I had tried creating the graphics myself at one point, but cloning didn't occur to me. 🙂

Thanks so much for your help!

Lisa
0 Kudos
ChrisSmith
Emerging Contributor
no worries and happy that it now works 🙂

regards

chris
0 Kudos
YingLin
Emerging Contributor
Yes. It works.
Thanks to both of you.
0 Kudos
GertConradie
Frequent Contributor
Hi Lisa/Others

Would it be possible to 'simulate' a screen rendering of an ESRI map control, ie completely in code behind: (No preview XAML used)
a) Programatically construct a new ESRI map control
b) Set the dimentions & Layers properties of the map control
c) Simulate the on screen rendering of the map control
d) Use ToBitmap() to create a WriteableBitmap from the control layers

The problem I have is that The ActualHeight/ActualWidth or RenderWidth/RenderHeight is 0, therefore the ToBitmap() return null every time.

I played a bit with adding the control to a parent Canvas or Grid controls and the calling the Measure / OnApplyTemplate / UpdateLayout methods, but no luck.

I know this is a more general Silverlight question but would appreciate any positive negative input.

Regards, g
            Size s = new Size(pixelWidth, pixelHeight);
            
            Canvas croot = new Canvas();
            croot.Height = pixelHeight;
            croot.Width = pixelWidth;
            ESRI.ArcGIS.Client.Map map = new Map();
            map.Progress += new EventHandler<ProgressEventArgs>(map_Progress);
            map.Height = pixelHeight;
            map.Width = pixelWidth;
            map.Layers = ClonedGraphicsLayerCollection;
            map.Extent = e.RequiredImageInformation.RequiredExtent.Extent;

            map.Measure(s);
            map.OnApplyTemplate();
            map.UpdateLayout();
            croot.Children.Add(map);
            croot.UpdateLayout();

            croot.Measure(s);
            croot.OnApplyTemplate();
            croot.UpdateLayout();
0 Kudos
GertConradie
Frequent Contributor
I were able to 'simulate' the screen draw of the map control, with a real screen draw - see my comment here: http://forums.silverlight.net/p/239340/595136.aspx/1?p=True&t=634523633636405968

The bigest problem was to identify when a FeatureLayer is really completed with drawing. I can post code if required by someone.

regards, g
0 Kudos