Tuesday 22 December 2015

arcmap - Updating MXD file using ArcObjects?


I'm using ArcGIS 9.3.1. product line and MXD files.


At our customer we have multiple environment (DEV, QAS, PROD) which should be more or less identical except they use different datbases and a few other minor tweaks. They alo share the same MXD file published as Map Services. These MXD should be the same, save for the fact their layer point to different data source (database) but with the same name & fields.


Now, to update map services we basically manually edit each MXD on all platform manually. This manual process is error prone and has caused trouble in the past. I'd like to edit the MXD document once and simply copy them on other platform. But then I'll need to pass them through some home made made custom tool to edit the data source.


I did write such a tool, it read the MXD document, find the used SDF file (connection file) and update the MXD's connetcion properties with the value from the local version of the SDE files.


It works well but for 1 problem. When I change a layer's data source, its fields loose their aliases and visibility flags, which are reset to the default.


I'd like to read the original value before update, update and then set the new values (to the old value)(for field's alias and visibility)


I try to cast my layers to ITableField, but I got FieldCount = 0!!! So I can't update anything!!!


Below is my current code (UpdateSDEWorkspaces is the method of interest) How could I set up the layer alias and visibility?



public static class MxdUtils
{
public static IEnumerable GetMaps(this IMapDocument pMapDocument)
{
int N = pMapDocument.MapCount;
for (int i = 0; i < N; i++)
yield return pMapDocument.get_Map(i);
}
public static IEnumerable GetLayers(this IMap pMap, UID uid, bool recursive)
{

IEnumLayer pEnumLayer = pMap.get_Layers(uid, recursive);
pEnumLayer.Reset();
for (ILayer pLayer = pEnumLayer.Next(); pLayer != null; pLayer = pEnumLayer.Next())
yield return pLayer;
}
public static IEnumerable GetLayers(this IMapDocument pMapDocument, UID uid, bool recursive)
{
return
from m in pMapDocument.GetMaps()
from l in m.GetLayers(uid, recursive)

select l;
}

///
/// Will update each SDE feature layer to the local sde connection.
/// It will will loop through all layer, find a layer's sde connection, if the local find can be found,
/// connection properties will be updated from it.
///

public static void UpdateSDEWorkspaces(string mxdPath) { UpdateSDEWorkspaces(mxdPath, null); }
public static void UpdateSDEWorkspaces(string mxdPath, Dictionary memory)

{
if (memory == null)
memory = new Dictionary();

IMapDocument pMapDocument = new MapDocumentClass();
pMapDocument.Open(mxdPath, "");

foreach (var pMap in pMapDocument.GetMaps())
{
var sdelayers =

from pLayer in pMap.GetLayers(new UID { Value = "{40A9E885-5533-11d0-98BE-00805F7CED21}" }, true)
let pFeatureLayer = pLayer as IFeatureLayer
where pFeatureLayer != null
let pDataLayer = pFeatureLayer as IDataLayer2
let pDatasetName = pDataLayer.DataSourceName as IDatasetName
where pDatasetName != null
let pWorkspaceName = pDatasetName.WorkspaceName
let pNewProp = GetConnectionProperties(memory, pWorkspaceName.PathName, mxdPath)
where pNewProp != null
select new

{
Layer = pLayer,
DataLayer = pDataLayer,
DSName = pDatasetName,
WorkspaceName = pWorkspaceName,
UpdatedProperties = pNewProp,
};

foreach (var item in sdelayers)
{

var tf = (ITableFields)item.Layer;
int N = tf.FieldCount;
// damn, why is N always 0?

item.WorkspaceName.ConnectionProperties = item.UpdatedProperties;
}

pMapDocument.ReplaceContents(pMap as IMxdContents);
}
pMapDocument.Save(true, false);

pMapDocument.Close();
}

public static IPropertySet GetConnectionProperties(Dictionary memory, string sdeConnPath, string mxdPath)
{
var path = sdeConnPath;
if (!File.Exists(path))
path = Path.Combine(Path.GetDirectoryName(mxdPath), Path.GetFileName(sdeConnPath));
if (!File.Exists(path))
path = Path.Combine(Environment.CurrentDirectory, Path.GetFileName(sdeConnPath));

if (!File.Exists(path))
return null;

IPropertySet set;
if (memory.TryGetValue(sdeConnPath, out set))
return set;

Console.WriteLine("Reading " + path);
set = GetSDEFactory().ReadConnectionPropertiesFromFile(path);
if (set == null)

return null;

memory[sdeConnPath] = set;
memory[path] = set;
return set;
}

static SdeWorkspaceFactoryClass GetSDEFactory()
{
if(SDEDataSourceFactory == null)

SDEDataSourceFactory = new SdeWorkspaceFactoryClass();
return SDEDataSourceFactory;
}
static SdeWorkspaceFactoryClass SDEDataSourceFactory;
}


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...