Load another mxd in current document

3214
3
06-30-2015 07:26 AM
BerendVeldkamp
Occasional Contributor II

Hi,

I am trying to write an addin that loads content (tables, featurelayers, relationships, ...) from an external mxd into the current ArcMap session. I do not want to actually load the mxd, because it would confuse users (they may be working on some mxd of their own, but after running my code it would point to my document).

Here is my code so far:

var reader = new MapReaderClass();
reader.Open(mxd.FullName);
var contents = reader.Map[0] as IMxdContents;
                   
// Test: write contents to external mxd, this works!
var mapOut = new MapDocumentClass();
mapOut.Open(@"D:\temp\untitled.mxd");
mapOut.ReplaceContents(contents);
mapOut.Save();

// Write contents to current document, this does not work!
var thisMapDoc = ArcMap.Document as IMapDocument; 
thisMapDoc.Map[0].ReplaceContents(contents);

reader.Close();

My problem is that copying the contents to another mxd works flawlessly, but copying it into the current document does not. Line 13 throws an exception, for some documents: Not implemented (Exception from HRESULT: 0x80004001 (E_NOTIMPL)), and for others The table does not have an OID Field. [NAME_OF_MY_TABLE] (One table does in fact have no OID field, but why that causes an error is beyond me).

I tried in both 10.1 and 10.3.1 with the same results.

0 Kudos
3 Replies
DuncanHornby
MVP Notable Contributor

Berend,

I think the problem comes from IMapDocument and its method ReplaceContents. It seems to be a method implemented by MapDocument class but not the MXDocument class.

Below is some VBA that transfers layers from one MapDocument into the currently running MXDocument.

Public Sub TransferLayers()
    ''' Get a handle on existing Map Document
    Dim pMapDocument As IMapDocument
    Set pMapDocument = New MapDocument
    pMapDocument.Open "C:\Scratch\Untitled.mxd"
   
    ''' Get a handle on the contents of this Map Document (assumed to be only 1 DataFrame)
    Dim pMXDContents As IMxdContents
    Set pMXDContents = pMapDocument.Map(0)
    Debug.Print pMXDContents.Map.LayerCount
   
    ''' Transfer layers into current MXD
    Dim pMXD As IMxDocument
    Set pMXD = ThisDocument
    Dim pLayer As ILayer
    Dim i As Integer
    For i = 0 To pMXDContents.Map.LayerCount - 1
        Set pLayer = pMXDContents.Map.Layer(i)
        Debug.Print pLayer.Name
        pMXD.FocusMap.AddLayer pLayer
    Next i
   
    ''' Refresh
    pMXD.UpdateContents
End Sub
0 Kudos
BerendVeldkamp
Occasional Contributor II

Hi Duncan,

Thanks for your reply.

It's strange though, the documentation clearly indicates that MxDocument implements IMapDocument. But maybe they never bothered to implement that particular method.

Copying layers is the easy part, and actually a oneliner:

pMXD.FocusMap.AddLayers(pMXDContents.Map.Layers, true);

but there's more to it than just that: Adding standalone tables, restoring relationshipclasses and joins, maybe more? It's not that it cannot be done, but I'd prefer to use IMapDocument, if at all possible .

0 Kudos
BerendVeldkamp
Occasional Contributor II

In case anyone is interested, I ended up loading the map using the MapReader class:

var reader = new MapReaderClass();
reader.Open(mxd);
var source = reader.Map[0];

Then copying the layers (IMap.AddLayers() messes up the original order):

for (var i = source.LayerCount; i > 0; i--)
{
    target.AddLayer(source.Layer[i - 1]);
}

And tables:

for (var i = 0; i < source.StandaloneTableCount; i++)
{
    target.AddStandaloneTable(source.StandaloneTable);
}

This way, any relationshipclass defined in the template mxd is imported automatically.

When loading the layers, the map will zoom out to the entire extent of the added layers. In order to avoid that, you need to set the map's spatial reference and extent (or scale, depending on what you want to do exactly) before adding any layers:

target.SpatialReference = source.SpatialReference;
target.MapScale = source.MapScale;

Also, to speed thing up a little:

ArcMap.Document.CurrentContentsView.ProcessEvents = false;

try
{
    // Load map here...
}
finally
{
    ArcMap.Document.CurrentContentsView.ProcessEvents = true;
    ArcMap.Document.CurrentContentsView.Refresh(null);
}
0 Kudos