|
POST
|
No, as you observe, the problem still exists at 100.5. At this point I'm just waiting to see if 100.6 fixes this problem.
... View more
07-30-2019
07:38 AM
|
0
|
0
|
1985
|
|
IDEA
|
Now that ArcGIS Runtime SDK supports annotation in mobile map packages, it would be nice to expose some more functionality. In particular, it would be useful to be able to change the color.
... View more
06-05-2019
08:39 AM
|
2
|
3
|
1583
|
|
POST
|
I finally took some time to look closer at this at 100.5, and it was a feedback occurring due to a two-way binding with the map scale. The fix was simple. UPDATE: I've attached a simpler example project duplicating the issue.
... View more
05-21-2019
07:08 AM
|
1
|
0
|
991
|
|
BLOG
|
Well! In my previous article, I presented a workaround for a bizarre MMPK bug that reappeared in version 100.5 of the ArcGIS Runtime SDK for .NET; but just when I thought I couldn't find another one even more unthinkably bizarre, up pops this: QueryRelatedFeaturesAsync will return a bad result when the FeatureLayer of a GeodatabaseFeatureTable is a sublayer of a GroupLayer. Huh? You can check out the attached Visual Studio project for confirmation, but in the meantime we have a conundrum. It would appear that, just when the GroupLayer class is finally implemented, we have to chuck it right back out until a safer, more effective version is delivered. I've updated an earlier article of mine to reflect that situation. Nonetheless, I got to thinking about how Runtime support for querying M:N relationships in a mobile map package didn't even start to appear until 100.4, and what I would need to do in order to support them were I still stuck at 100.3. Or, what if QueryRelatedFeaturesAsync were to fail again in a future version? Supporting one-to-one and one-to-many relationships is actually fairly simple, since the RelationshipInfo class gives the required information, when retrieved from both origin and destination tables. But many-to-many relationships are entirely another can of worms, because some crucial information is inaccessible via Runtime, even though it's encoded in the geodatabase. Contrary to the wording in the documentation for the RelationshipInfo class [and I quote: "A relationship consists of two and only two tables"], M:N relationships involve a third, intermediate table. Querying M:N relationships requires knowledge to query that intermediate table, and that's precisely the information which is withheld from the Runtime developer. Let's take a look at how relationships are stored in a mobile map package. In my previous article, I introduced you to the GDB_ServiceItems table. The ItemInfo field in that table stores the JSON data used to hydrate the ArcGISFeatureLayerInfo class: Here's the JSON that describes the RegulatorStation to GasValve relationship from the origin role: {
"id": 4,
"name": "Gas Valve",
"relatedTableId": 10,
"cardinality": "esriRelCardinalityManyToMany",
"role": "esriRelRoleOrigin",
"keyField": "OBJECTID",
"composite": false,
"relationshipTableId": 73,
"keyFieldInRelationshipTable": "REGSTATIONOBJECTID"
} And here's the description for destination role: {
"id": 4,
"name": "Regulator Station",
"relatedTableId": 13,
"cardinality": "esriRelCardinalityManyToMany",
"role": "esriRelRoleDestination",
"keyField": "OBJECTID",
"composite": false,
"relationshipTableId": 73,
"keyFieldInRelationshipTable": "GASVALVEOBJECTID"
} The two crucial items that are not included in the RelationshipInfo class are relationshipTableId and keyFieldInRelationshipTable. But how to get at that information in your app? Aye, there's the rub. In short, you need to extract the geodatabase from the mobile map package and query the GDB_ServiceItems table directly. That's where you need a library such as System.Data.SQLite, which is available via the NuGet Package Manager: Given the necessary tools, the first step is to extract the geodatabase to a temporary location: public async Task Init(string sMMPKPath, Geodatabase gdb)
{
string sGDBPath = gdb.Path;
string sGDBName = Path.GetFileName(sGDBPath);
string sTempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(sTempDir);
string sTempPath = Path.Combine(sTempDir, sGDBName);
using (ZipArchive zip = ZipFile.OpenRead(sMMPKPath))
{
ZipArchiveEntry zipEntry = zip.GetEntry(sGDBPath);
zipEntry.ExtractToFile(sTempPath);
}
Next, query the desired information, taking the steps necessary to clean up afterwards: List<string> ItemInfos = new List<string>();
string sConn = "Data Source=" + sTempPath + ";Read Only=True";
string sSQL = "SELECT ItemInfo FROM GDB_ServiceItems";
using (SQLiteConnection sqlConn = new SQLiteConnection("Data Source=" + sTempPath))
{
sqlConn.Open();
using (SQLiteCommand sqlCmd = new SQLiteCommand(sSQL, sqlConn))
{
using (SQLiteDataReader sqlReader = sqlCmd.ExecuteReader())
{
while (sqlReader.Read())
ItemInfos.Add(sqlReader.GetString(0));
sqlReader.Close();
}
}
sqlConn.Close();
}
GC.Collect();
GC.WaitForPendingFinalizers();
Directory.Delete(sTempDir, true);
Finally, combine the missing ingredients with the out-of-the-box information: _infos = new Dictionary<long, Dictionary<long, ExtendedRelationshipInfo>>();
foreach (string sInfo in ItemInfos)
{
Dictionary<string, object> info = _js.DeserializeObject(sInfo) as Dictionary<string, object>;
if (!info.ContainsKey("relationships"))
continue;
object[] relationships = info["relationships"] as object[];
if (relationships.Length == 0)
continue;
long iTableID = Convert.ToInt64(info["id"]);
// Get basic table relationship infos
GeodatabaseFeatureTable gfTab = gdb.GeodatabaseFeatureTable(iTableID);
if (gfTab.LoadStatus != Esri.ArcGISRuntime.LoadStatus.Loaded)
await gfTab.LoadAsync();
Dictionary<long, RelationshipInfo> BasicInfos = new Dictionary<long, RelationshipInfo>();
foreach (RelationshipInfo relInfo in gfTab.LayerInfo.RelationshipInfos)
BasicInfos[relInfo.Id] = relInfo;
// Add extended data
Dictionary<long, ExtendedRelationshipInfo> ExtendedInfos = new Dictionary<long, ExtendedRelationshipInfo>();
foreach (object obj in relationships)
{
Dictionary<string, object> rel = obj as Dictionary<string, object>;
long iRelID = Convert.ToInt64(rel["id"]);
string sCard = rel["cardinality"].ToString();
long? iRelTableID = null;
string sKeyField = null;
if (sCard == "esriRelCardinalityManyToMany")
{
iRelTableID = Convert.ToInt64(rel["relationshipTableId"]);
sKeyField = rel["keyFieldInRelationshipTable"].ToString();
}
ExtendedRelationshipInfo erInfo = new ExtendedRelationshipInfo()
{
BasicInfo = BasicInfos[iRelID],
RelationshipTableId = iRelTableID,
KeyFieldInRelationshipTable = sKeyField
};
ExtendedInfos[iRelID] = erInfo;
}
_infos[iTableID] = ExtendedInfos;
} // foreach
Here, then, is the code for querying related features: public async Task<FeatureQueryResult> QueryRelated(ArcGISFeature feat, long iRelID)
{
// Get relationship data
if (!(feat.FeatureTable is GeodatabaseFeatureTable gfTabSource))
return null;
long iTableID = gfTabSource.LayerInfo.ServiceLayerId;
if (!_infos.ContainsKey(iTableID))
return null;
Dictionary<long, ExtendedRelationshipInfo> ExtendedInfos = _infos[iTableID];
if (!ExtendedInfos.ContainsKey(iRelID))
return null;
ExtendedRelationshipInfo extInfoSource = ExtendedInfos[iRelID];
RelationshipInfo infoSource = extInfoSource.BasicInfo;
long iRelTableID = infoSource.RelatedTableId;
if (!_infos.ContainsKey(iRelTableID))
return null;
ExtendedInfos = _infos[iRelTableID];
if (!ExtendedInfos.ContainsKey(iRelID))
return null;
ExtendedRelationshipInfo extInfoTarget = ExtendedInfos[iRelID];
RelationshipInfo infoTarget = extInfoTarget.BasicInfo;
// Build query
string sKeyValSource = feat.GetAttributeValue(infoSource.KeyField).ToString();
Geodatabase gdb = gfTabSource.Geodatabase;
GeodatabaseFeatureTable gfTabTarget = gdb.GeodatabaseFeatureTable(iRelTableID);
string sKeyFieldTarget = infoTarget.KeyField;
Field fieldKeyTarget = gfTabTarget.GetField(sKeyFieldTarget);
StringBuilder sb = new StringBuilder();
sb.Append(sKeyFieldTarget);
if (infoSource.Cardinality == RelationshipCardinality.ManyToMany)
{
// Gather key values from intermediate table
GeodatabaseFeatureTable gfTabRel = gdb.GeodatabaseFeatureTable(extInfoSource.RelationshipTableId.Value);
string sKeyFieldRelSource = extInfoSource.KeyFieldInRelationshipTable;
Field fieldRelSource = gfTabRel.GetField(sKeyFieldRelSource);
string sWhere = sKeyFieldRelSource + " = " + sKeyValSource;
if (fieldRelSource.FieldType == FieldType.Guid)
sWhere = sKeyFieldRelSource + " = '" + sKeyValSource + "'";
QueryParameters qpRel = new QueryParameters() { WhereClause = sWhere };
FeatureQueryResult resultRel = await gfTabRel.QueryFeaturesAsync(qpRel);
if (resultRel.Count() == 0)
return resultRel;
string sKeyFieldRelTarget = extInfoTarget.KeyFieldInRelationshipTable;
Field fieldRelTarget = gfTabRel.GetField(sKeyFieldRelTarget);
sb.Append(" IN ( ");
bool bFirst = true;
foreach (Feature featRel in resultRel)
{
if (bFirst)
bFirst = false;
else
sb.Append(", ");
string sKeyValTarget = featRel.GetAttributeValue(sKeyFieldRelTarget).ToString();
if (fieldRelTarget.FieldType == FieldType.Guid)
sb.Append("'" + sKeyValTarget + "'");
else
sb.Append(sKeyValTarget);
}
sb.Append(" ) ");
}
else
{
sb.Append(" = ");
if (fieldKeyTarget.FieldType == FieldType.Guid)
sb.Append("'" + sKeyValSource + "'");
else
sb.Append(sKeyValSource);
}
// Query related features
QueryParameters qp = new QueryParameters() { WhereClause = sb.ToString() };
return await gfTabTarget.QueryFeaturesAsync(qp);
} Needless to say, this is a pretty extreme approach to take. Nonetheless, you never know when this knowledge may come in useful. UPDATE: It occurred to me that since I routinely automate MMPK creation using Python, I could also create companion files containing the many-to-many relationships. I've added a new attachment that contains both a Python script and a revised version of the RelationshipHelper class that takes advantage of it. Now it's more feasible to support both group layers and related feature queries.
... View more
05-16-2019
09:04 AM
|
0
|
2
|
954
|
|
BLOG
|
UPDATE: The example project has been updated with an option to allow older (pre-100.5) behavior, where instead of actually creating group layers, the app has TOC items imitate them. This is a workaround for a recently discovered 100.5 bug that affects the ability of sublayers of a group layer to query related records.
... View more
05-15-2019
01:20 PM
|
0
|
0
|
779
|
|
POST
|
I figured it out!!!! QueryRelatedFeaturesAsync will not work if the FeatureLayer is a sublayer of a GroupLayer. Here's the example code: using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Esri.ArcGISRuntime.ArcGISServices;
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.UI.Controls;
namespace RelTest
{
static class MobileMapTest
{
static readonly bool bAddGroupLayers = true;
const string sMMPKPath = @"C:\apps\FieldApp\Data";
static readonly string[] MMPKNames = { "AZLandbase.mmpk", "AZGas.mmpk" };
const int iMapIndex = 0;
const int iRelID = 4;
const string sForwardTableName = "RegulatorStation";
const int iForwardFeatureID = 2912;
public static async Task OpenMMPK()
{
// Open mobile map
MapView mv = MainWindowModel.Current.MapViewContainerContent;
Map MyMap = new Map();
Viewpoint vp = null;
foreach (string sMMPKName in MMPKNames)
{
string sMMPK = Path.Combine(sMMPKPath, sMMPKName);
MobileMapPackage mmpk = await MobileMapPackage.OpenAsync(sMMPK);
Map map = mmpk.Maps[iMapIndex];
if (vp == null)
vp = map.InitialViewpoint;
LayerCollection Sublayers;
if (bAddGroupLayers)
{
GroupLayer gLyr = new GroupLayer()
{
Name = Path.GetFileNameWithoutExtension(sMMPKName),
Id = Guid.NewGuid().ToString(),
IsVisible = true
};
MyMap.OperationalLayers.Add(gLyr);
Sublayers = gLyr.Layers;
}
else
Sublayers = MyMap.OperationalLayers;
foreach (Layer lyr in map.OperationalLayers.ToList())
{
map.OperationalLayers.Remove(lyr);
Sublayers.Add(lyr);
}
}
MyMap.InitialViewpoint = vp;
mv.Map = MyMap;
await MyMap.LoadAsync();
}
public static async Task QueryTest()
{
// Get feature layer
MapView mv = MainWindowModel.Current.MapViewContainerContent;
FeatureLayer fLyr = FindLayer(mv.Map.OperationalLayers, sForwardTableName);
if (fLyr == null)
return;
ArcGISFeatureTable fTab = fLyr.FeatureTable as ArcGISFeatureTable;
// Get feature for forward test
QueryParameters qp = new QueryParameters();
qp.ObjectIds.Add(iForwardFeatureID);
FeatureQueryResult queryResult = await fTab.QueryFeaturesAsync(qp);
ArcGISFeature feat = queryResult.FirstOrDefault() as ArcGISFeature;
// Get forward M:N relationship
RelationshipInfo relInfo = null;
foreach (RelationshipInfo info in fTab.LayerInfo.RelationshipInfos)
{
if (info.Id != iRelID)
continue;
relInfo = info;
break;
}
// Forward related query test
// 100.5 BUG: This will fail if the feature layer is a sublayer of a group layer
RelatedQueryParameters param = new RelatedQueryParameters(relInfo);
bool bForwardSuccess = true;
IReadOnlyList<RelatedFeatureQueryResult> Results = await fTab.QueryRelatedFeaturesAsync(feat, param);
if (Results == null)
bForwardSuccess = false;
else if (Results.Count == 0)
bForwardSuccess = false;
else
{
RelatedFeatureQueryResult relResult = Results.FirstOrDefault();
bForwardSuccess = (relResult.Count() > 0);
}
StringBuilder sb = new StringBuilder();
sb.Append("Query test (with");
if (!bAddGroupLayers)
sb.Append("out");
sb.Append(" group layers): ");
if (bForwardSuccess)
sb.Append("Success");
else
sb.Append("Fail");
MessageBox.Show(sb.ToString());
}
private static FeatureLayer FindLayer(IEnumerable<Layer> Layers, string sTableName)
{
foreach (Layer lyr in Layers)
{
if (lyr is FeatureLayer fLyr)
{
if (!(fLyr.FeatureTable is ArcGISFeatureTable fTab))
continue;
if (fTab.TableName != sTableName)
continue;
return fLyr;
}
else if (lyr is GroupLayer gLyr)
{
FeatureLayer fl = FindLayer(gLyr.Layers, sTableName);
if (fl == null)
continue;
return fl;
}
}
return null;
}
}
}
... View more
05-14-2019
08:11 AM
|
0
|
0
|
1182
|
|
POST
|
At 100.5, no m:n related features are returned at all from a mmpk. Now my mmpk queries are working fine in both directions. I don't know what I was doing wrong before. Also, querying m:n related features from a service feature table exhibits interesting behavior: 1) If a related feature is found, multiple duplicate results are returned 2) If a related feature is not found, the query throws an "Item not found in database" exception 3) Nonetheless, the query does work in both directions, M>N and N>M.
... View more
05-09-2019
03:28 PM
|
0
|
1
|
1182
|
|
POST
|
https://pro.arcgis.com/en/pro-app/help/sharing/overview/mobile-map-package.htm
... View more
05-02-2019
03:58 PM
|
2
|
0
|
1253
|
|
POST
|
You have to convert the annotation to Pro annotation. I use a Python script that creates a file geodatabase and performs the conversion before calling the create MMPK tool.
... View more
05-02-2019
03:39 PM
|
2
|
1
|
1253
|
|
BLOG
|
In my previous article, I presented a workaround for preserving group layers in a mobile map opened using ArcGIS Runtime SDK for .NET 100.5. Today's topic involves something a bit nastier. It can be pretty frustrating when a bug that is fixed in an earlier software version reappears in a later one. The lesson here is: Never discard your workaround code! The bug in question involves certain multi-layer marker symbols that are not rendered properly when rotated. For example, see this symbol as shown in the original ArcGIS Pro project: Here's how it looks when exported to a mobile map package and opened using ArcGIS Runtime (see the attached Visual Studio example project): Yikes! This problem was identified at 100.1 and fixed in 100.2, but at 100.5 once more it rears its ugly head. One workaround is to set ArcGISFeatureTable.UseAdvancedSymbology to false. This causes marker symbols to be rendered as picture markers. That's fine until you run into two limitations. The first is when you set a reference scale and zoom in: But even more challenging, what if you want to change symbol colors on the fly? In theory, you can do that with a bitmap, but it's beyond my skill to deal with the dithering: There's another approach, but until Esri implements more fine-grained class properties and methods, manipulating symbols involves a lot of JSON hacking. Before I go any further, let's crack open a mobile map package and see where drawing information is stored. If you examine the mobile geodatabase using a tool such as SQLiteSpy, you will see a table called GDB_ServiceItems: That's the raw JSON for the data retrieved by ArcGISFeatureTable.LayerInfo.DrawingInfo. Fortunately, there's no need to hack into the table, because you can get the renderer for a feature layer, retrieve the symbol(s), and convert them to JSON. Then you make whatever edits you want, and create a new symbol. public static Symbol UpdateSymbolJSON(MultilayerPointSymbol symOld, Color colorOld, Color colorNew)
{
string sOldJSON = symOld.ToJson();
Dictionary<string, object> dict = (Dictionary<string, object>)_js.DeserializeObject(sOldJSON);
SymbolHelper.ProcessObjectColorJSON(dict, colorOld, colorNew);
string sNewJSON = _js.Serialize(dict);
Symbol symNew = Symbol.FromJson(sNewJSON);
return symNew;
}
So what's the workaround? The nature of the bug seems to be an inability to process offsetX and offsetY correctly. In fact, they seem to be reversed. So let's see what happens when the offsets are reversed in the JSON: Nope. Not quite there. What I finally ended up doing is to combine the offset layers into a single layer with no offsets. Fortunately again, characters are already converted to polygons in the JSON, or I would be doing a lot more work. First, I collect the offset layers and find the smallest interval (points per coordinate unit): bool[] Offset = new bool[layers.Length];
List<OffsetLayer> OffsetLayers = new List<OffsetLayer>();
double dInterval = double.MaxValue;
for (int i = 0; i < layers.Length; i++)
{
Dictionary<string, object> lyr = layers[i] as Dictionary<string, object>;
// Check for X and/or Y offset
bool bOffset = false;
double dOffsetX = 0;
double dOffsetY = 0;
if (lyr.ContainsKey("offsetX"))
{
dOffsetX = Convert.ToDouble(lyr["offsetX"]);
lyr["offsetX"] = 0;
bOffset = true;
}
if (lyr.ContainsKey("offsetY"))
{
dOffsetY = Convert.ToDouble(lyr["offsetY"]);
lyr["offsetY"] = 0;
bOffset = true;
}
Offset[i] = bOffset;
if (!bOffset)
continue;
// Get offset layer data
Dictionary<string, object> frame = lyr["frame"] as Dictionary<string, object>;
object[] markerGraphics = lyr["markerGraphics"] as object[];
Dictionary<string, object> markerGraphic = markerGraphics[0] as Dictionary<string, object>;
Dictionary<string, object> geometry = markerGraphic["geometry"] as Dictionary<string, object>;
object[] rings = geometry["rings"] as object[];
int ymin = Convert.ToInt32(frame["ymin"]);
int ymax = Convert.ToInt32(frame["ymax"]);
double size = Convert.ToDouble(lyr["size"]);
double dInt = size / (ymax - ymin);
if (dInt < dInterval)
dInterval = dInt;
OffsetLayer layer = new OffsetLayer()
{
offsetX = dOffsetX,
offsetY = dOffsetY,
xmin = Convert.ToInt32(frame["xmin"]),
ymin = ymin,
xmax = Convert.ToInt32(frame["xmax"]),
ymax = ymax,
size = size,
rings = rings
};
OffsetLayers.Add(layer);
} // for
Then I set up the combined frame and recalculate the ring coordinates: int iMinX = 0;
int iMinY = 0;
int iMaxX = 0;
int iMaxY = 0;
List<object[]> OffsetRings = new List<object[]>();
foreach (OffsetLayer lyr in OffsetLayers)
{
double dX, dY;
int iX, iY;
// Set up transformation
double dInt = lyr.size / (lyr.ymax - lyr.ymin);
double dOffsetX = lyr.offsetX / dInt;
double dOffsetY = lyr.offsetY / dInt;
double dScale = dInt / dInterval;
dX = (lyr.xmin + dOffsetX) * dScale;
iX = (int)dX;
if (iX < iMinX)
iMinX = iX;
dX = (lyr.xmax + dOffsetX) * dScale;
iX = (int)dX;
if (iX > iMaxX)
iMaxX = iX;
dY = (lyr.ymin + dOffsetY) * dScale;
iY = (int)dY;
if (iY < iMinY)
iMinY = iY;
dY = (lyr.ymax + dOffsetY) * dScale;
iY = (int)dY;
if (iY > iMaxY)
iMaxY = iY;
// Recalculate rings
foreach (object obj in lyr.rings)
{
object[] ring = obj as object[];
foreach (object o in ring)
{
object[] pt = o as object[];
pt[0] = (int)((Convert.ToInt32(pt[0]) + dOffsetX) * dScale);
pt[1] = (int)((Convert.ToInt32(pt[1]) + dOffsetY) * dScale);
}
OffsetRings.Add(ring);
}
} // foreach
double dSize = (iMaxY - iMinY) * dInterval;
Finally, I assemble a new symbol layer list: List<object> NewLayers = new List<object>();
bool bFirst = true;
for (int i = 0; i < layers.Length; i++)
{
if (!Offset[i])
{
NewLayers.Add(layers[i]);
continue;
}
else if (!bFirst)
continue;
// Update first offset layer
Dictionary<string, object> lyr = layers[i] as Dictionary<string, object>;
Dictionary<string, object> frame = lyr["frame"] as Dictionary<string, object>;
frame["xmin"] = iMinX;
frame["ymin"] = iMinY;
frame["xmax"] = iMaxX;
frame["ymax"] = iMaxY;
lyr["size"] = dSize;
if (lyr.ContainsKey("offsetX"))
lyr["offsetX"] = 0;
if (lyr.ContainsKey("offsetY"))
lyr["offsetY"] = 0;
NewLayers.Add(lyr);
object[] markerGraphics = lyr["markerGraphics"] as object[];
Dictionary<string, object> markerGraphic = markerGraphics[0] as Dictionary<string, object>;
Dictionary<string, object> geometry = markerGraphic["geometry"] as Dictionary<string, object>;
geometry["rings"] = OffsetRings.ToArray();
bFirst = false;
} // for
return NewLayers.ToArray();
And here are the results: Much better. I can't guarantee that this code will work for every situation, but it seems to work fine for my own complex symbols. And remember: even if this bug is fixed at 100.6, hang onto this code, in case you need it again in the future!
... View more
05-02-2019
02:40 PM
|
0
|
2
|
1249
|
|
POST
|
Looks like this problem has resurfaced in 100.5. The old 100.1 workaround fixes it.
... View more
04-23-2019
10:20 AM
|
0
|
0
|
1081
|
|
POST
|
MMPK annotation looks good. If I were add a wish item, it would be the ability to apply a color override.
... View more
04-23-2019
09:49 AM
|
0
|
0
|
861
|
|
POST
|
I notice that Arcade expressions for display fields don't come across in a mobile map package. However, this is a very minor issue, since I can use the same expression in the popup title and it works fine. It's nice to use PopupManager and see subtype and domain values displaying properly.
... View more
04-23-2019
07:27 AM
|
0
|
1
|
1041
|
|
POST
|
To try to explain the situation better: in the past, I've routinely loaded layers to get their info before adding them to the map. At 100.5, this can break layer behavior, especially if a reference scale is defined. I've come up with a workaround, but it's a bit clumsy, and I'm still trying to work out a more elegant way to get what I want..
... View more
04-18-2019
03:25 PM
|
0
|
0
|
840
|
|
POST
|
I notice that the GroupLayer class at 100.5 has a quirk similar that of an earlier (pre-10.2.7) release: when a sublayer has labels enabled and the group layer is initially not visible, the labels still appear. However, when the layer is made visible and then not visible again, the labels go away. Is there a better practice for creating and adding group layers?
... View more
04-18-2019
03:12 PM
|
0
|
1
|
926
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 01-04-2012 06:42 AM | |
| 1 | 09-23-2021 10:42 AM | |
| 2 | 09-28-2021 07:07 AM | |
| 1 | 04-07-2021 10:31 PM | |
| 3 | 03-21-2021 01:14 PM |
| Online Status |
Offline
|
| Date Last Visited |
01-07-2022
08:31 AM
|