Select to view content in your preferred language

start ArcMap/load layers from standalone C# application

4106
9
07-13-2011 03:08 AM
CarlosPiccirillo
Emerging Contributor
Hi everyone,

I am writing a standalone application in C# for creating automated jpg maps. Originally, the code was in VBA and I am converting it to C#. I've written a couple of other standalone applications in C# where I queried and edited data but in those I was able to do it without having to call up ArcMap. Unforunately, I think for working with layouts, graphics, etc., I have to use ArcMap. If I am mistaken in this, please correct me.

Anyhow, here's my problem. I can start ArcMap in code and load seveal SDE layers into it. The problem occurs when I try to do anything with the layers in the TOC. If I try to open an attribute table or change symbology, the screen flashes, all of the names of the layers in the TOC go away and all I am left with is the on/off checkbox with the red broken link exclamation mark next to each layer. After a few seconds, ArcMap crashes.

I've seen a couple of similiar posts in the old forums but no solutions. Anyone have an idea of what I am doing wrong?

Below is my code for starting ArcMap and loading SDE layers plus a screen capture of the error when ArcMap crashes.

Thanks for your time,
Carlos

internal static void StartArcMap()
{
    try
    {
 m_MxDocument = new MxDocumentClass();
 m_application = ((IDocument)m_MxDocument).Parent;
 m_application.Visible = true;

 // Wait for ArcMap to initialize before continuing.
 System.Windows.Forms.Application.DoEvents();
    }
    catch (Exception ex)
    {
 MessageBox.Show(ex.Message);
    }
}



internal static ILayer AddSDEFeatureClass(string server, string instance, string user,
       string password, string version, string featureClassName, 
       string tocName, short transparency, bool labels,
       bool visibility, bool selectability)
{
    try
    {
 IPropertySet pPropertySet = new PropertySetClass();
 pPropertySet.SetProperty("SERVER", server);
 pPropertySet.SetProperty("INSTANCE", instance);
 pPropertySet.SetProperty("USER", user);
 pPropertySet.SetProperty("PASSWORD", password);
 pPropertySet.SetProperty("VERSION", version);

 IWorkspaceFactory pWorkspaceFactory = new SdeWorkspaceFactoryClass();
 IFeatureWorkspace pFeatureWorkspace = pWorkspaceFactory.Open(pPropertySet, 0) as IFeatureWorkspace;
 IFeatureClass pFeatureClass = pFeatureWorkspace.OpenFeatureClass(featureClassName);

 IFeatureLayer pFeatureLayer = new FeatureLayerClass();
 pFeatureLayer.FeatureClass = pFeatureClass;
 m_MxDocument.FocusMap.AddLayer(pFeatureLayer);
 IGeoFeatureLayer pGeoFeatureLayerOut = pFeatureLayer as IGeoFeatureLayer;

 // Apply TOC name.
 pGeoFeatureLayerOut.Name = tocName;

 // Set transparency.
 ILayerEffects pLayerEffects = pFeatureLayer as ILayerEffects;
 pLayerEffects.Transparency = transparency;

 // Collapse the layer in the TOC.
 ILegendInfo pLegendInfo = pGeoFeatureLayerOut as ILegendInfo;
 ILegendGroup pLegendGroup = new LegendGroupClass();
 pLegendGroup = pLegendInfo.get_LegendGroup(0);
 pLegendGroup.Visible = false;

 // if labels = true, turn labels on, otherwise off.
 if (labels == true)
     pGeoFeatureLayerOut.DisplayAnnotation = true;
 else
     pGeoFeatureLayerOut.DisplayAnnotation = false;

 // If visibility = true, turn layer on, otherwise off.
 if (visibility == true)
     pGeoFeatureLayerOut.Visible = true;
 else
     pGeoFeatureLayerOut.Visible = false;

 // If selectability = true, turn layer on, otherwise off.
 if (selectability == true)
     pGeoFeatureLayerOut.Selectable = true;
 else
     pGeoFeatureLayerOut.Selectable = false;

 m_MxDocument.ActiveView.Refresh();
 m_MxDocument.UpdateContents();

 return pGeoFeatureLayerOut;

    }   //end try
    catch (Exception ex)
    {
 MessageBox.Show(ex.Message);
 return null;
    }
}
0 Kudos
9 Replies
NeilClemmons
Honored Contributor
You can't use New to create instances of the objects you will be using in conjunction with the ArcMap application..  You need to be using IObjectFactory.  Your application and ArcMap are running in seperate processes.  All ArcObjects are single apartment threaded, meaning they will not marshal correctly when used across process boundaries.  Therefore, you will need to create the ArcObjects instances in ArcMap's process space, not your application's process space.  IObjectFactory will do this for you.  There is a developer sample on Automation that you might want to look at.
0 Kudos
CarlosPiccirillo
Emerging Contributor
Thanks Neil, I am looking at the developer sample Automation example now. Does this mean I have to use IObjectFactory for every new ArcObject I create?

One more question if you don't mind, a few months ago you got me on the right track of writing the stand alone C# application I was refering to in my original message where I didn't need to load ArcMap to do what I needed to do, queries and edits. Do you know if can use the same approach in my new application where I will be producing automated maps in jpg format or if I need to start ArcMap to get to layout, graphics, etc.?

Thanks again for you help!!!
Carlos

You can't use New to create instances of the objects you will be using in conjunction with the ArcMap application..  You need to be using IObjectFactory.  Your application and ArcMap are running in seperate processes.  All ArcObjects are single apartment threaded, meaning they will not marshal correctly when used across process boundaries.  Therefore, you will need to create the ArcObjects instances in ArcMap's process space, not your application's process space.  IObjectFactory will do this for you.  There is a developer sample on Automation that you might want to look at.
0 Kudos
NeilClemmons
Honored Contributor
Yes, you need to use IObjectFactory to create all instances of the ArcObjects that will be used in conjunction with the ArcMap application.

If you have a map document created that has all of the layers, symbology, layout elements, etc that you need then you can use IMapDocument to open the document and work with it.  This includes zooming the map frames to various extents and exporting the layout.  You can also manipulate the layout by adding elements or modifying existing elements.  Things can get complicated if you need to create layouts from scratch every time but it's about the same level of effort trying to do the same thing by automating ArcMap.  I've never run into a case where automating ArcMap was needed and I would try to avoid it like the plague.  ArcMap wasn't designed to be automated and the whole process is flaky and, in my opinion, a lot more trouble than it's worth.
0 Kudos
CarlosPiccirillo
Emerging Contributor
Yeah, I would prefer to avoid using ArcMap altogether if I can get away with it. Unfortunately, no I don't have a map document that has layers, symbology, etc. that I need. In the original VBA code, the mxd had all the code in it and it would fire off from OpenDocument. First it would load all necessary layers, then run queries and finally, apply layer files to the desired layers and produce jpg maps. It worked fantastic in VBA but unfortunately, the transfer to C# isn't going so smoothly.

Yes, you need to use IObjectFactory to create all instances of the ArcObjects that will be used in conjunction with the ArcMap application.

If you have a map document created that has all of the layers, symbology, layout elements, etc that you need then you can use IMapDocument to open the document and work with it.  This includes zooming the map frames to various extents and exporting the layout.  You can also manipulate the layout by adding elements or modifying existing elements.  Things can get complicated if you need to create layouts from scratch every time but it's about the same level of effort trying to do the same thing by automating ArcMap.  I've never run into a case where automating ArcMap was needed and I would try to avoid it like the plague.  ArcMap wasn't designed to be automated and the whole process is flaky and, in my opinion, a lot more trouble than it's worth.
0 Kudos
MichaelRobb
Honored Contributor
ArcMap wasn't designed to be automated and the whole process is flaky and, in my opinion, a lot more trouble than it's worth.


After a few years of somewhat achieving full automation, which in some rare cases is really handy (such as I have automated where as a sent email from a client triggers eventual data xy created by info in the email, open arc, create features, attributes, place in cleint gdb, create a compiled layout and pdf back to the emailer and close - no one needs to be around, just the computer on)

otherwise I completely agree with Neil...
0 Kudos
NeilClemmons
Honored Contributor
Have you tried creating a new instance of the Map class and adding a couple of layers to it then exporting it as a jpg image?  If that works, then you can add all of the additional code.
0 Kudos
CarlosPiccirillo
Emerging Contributor
No I haven't tried that. To be honest, not sure I know how to do that. Do you have some sample code I could look at to get started even if it's VB6, VB.NET or VBA?


Have you tried creating a new instance of the Map class and adding a couple of layers to it then exporting it as a jpg image?  If that works, then you can add all of the additional code.
0 Kudos
NeilClemmons
Honored Contributor
You just create a new map object.  I'm assuming your original code worked with a map reference that you got from IMxDocument.FocusMap.  None of that code logic would change except that you're creating a new map instead of using one you got from ArcMap.

Dim map As IMap = new Map

The code to create the layer objects should be pretty much the same as what you were originally doing, just add them to this map instead.  Also use this map to get your IActiveView references and any others that you were originally getting from the ArcMap document's FocusMap.
0 Kudos
CarlosPiccirillo
Emerging Contributor
Neil,

You are correct, I was getting a map reference from IMxDocument.FocusMap.

Thanks for pointing me in the right direction, I will give it a try.

Carlos

You just create a new map object.  I'm assuming your original code worked with a map reference that you got from IMxDocument.FocusMap.  None of that code logic would change except that you're creating a new map instead of using one you got from ArcMap.

Dim map As IMap = new Map

The code to create the layer objects should be pretty much the same as what you were originally doing, just add them to this map instead.  Also use this map to get your IActiveView references and any others that you were originally getting from the ArcMap document's FocusMap.
0 Kudos