It's been discussed that attempting to print a map where the extent contains text graphics with custom attributes will fail, usually with an error like "Field '<Field Name>' not part of schema for this feature collection". This isn't a remotely elegant solution whatsoever, but I wanted to pass on what I did to hack around this limitation in case anyone else was facing it. The gist of it is to clear out the custom attributes from the text symbols before the print starts, and to replace them after the print is completed, using the geometry of the graphics as a unique key (of course assuming all graphics will have at least a slightly different point geometry).
Dictionary<GraphicsLayer, Dictionary<ESRI.ArcGIS.Client.Geometry.MapPoint, Dictionary<string, object>>> textSymbolAttributes = null;
In the method that starts the print task:
LayerCollection lc = MapObject.Layers;
for (int x = 0; x < lc.Count; x++)
{
if (lc is GraphicsLayer)
{
GraphicsLayer gl = (GraphicsLayer)lc;
if (gl.Graphics.Count > 0)
{
//for whatever reason text symbols will not print if they have custom attributes
//there's no completely foolproof way to strip out the attributes now and replace them later
//but it's safe to assume that the geometry will always be slightly different
foreach (Graphic g in gl.Graphics)
{
if (g.Symbol is TextSymbol)
{
if (textSymbolAttributes == null) textSymbolAttributes = new Dictionary<GraphicsLayer, Dictionary<MapPoint, Dictionary<string, object>>>();
if (!textSymbolAttributes.ContainsKey(gl)) textSymbolAttributes.Add(gl, new Dictionary<MapPoint, Dictionary<string, object>>());
Dictionary<string, object> copyDict = new Dictionary<string,object>();
foreach(var dictEntry in g.Attributes) copyDict.Add(dictEntry.Key, dictEntry.Value);
textSymbolAttributes[gl].Add(g.Geometry as MapPoint, copyDict);
g.Attributes.Clear();
}
}
}
}
}
After the print job has completed, replace the custom attributes. Because we don't have any real unique ID to use as a key, I'm going under the assumption that no two graphics will have the exact same point location.
In the PrintCompleted method:
LayerCollection lc = MapObject.Layers;
for (int x = 0; x < lc.Count; x++)
{
if (lc is GraphicsLayer)
{
GraphicsLayer gl = (GraphicsLayer)lc;
//check to see if the current graphics layer is contained in the dictionary
if (textSymbolAttributes != null && textSymbolAttributes.ContainsKey(gl))
{
foreach (Graphic g in gl.Graphics)
{
//only look at text symboles
if (g.Symbol is TextSymbol)
{
MapPoint mp = (MapPoint)g.Geometry;
foreach (var kvp in textSymbolAttributes[gl])
{
//assuming no two text symbols within the same graphics layer wont have identical geometry, we can replace our attributes now that the print is over
if (mp.X == kvp.Key.X & mp.Y == kvp.Key.Y)
{
foreach (var kvp2 in kvp.Value)
{
g.Attributes.Add(kvp2.Key, kvp2.Value);
}
}
}
}
}
}
}
}