I discovered the string value “[#ColumnName#]” by browsing the forums, which places the value in the featuresource’s column for a particular feature in its place. I used this for setting the Text property of a WebImage belonging to markers in an InMemoryMarkerOverlay and I believe I have seen it first used for setting the Label of a InMemoryFeatureLayer. This seems incredibly powerful and useful.
Why is this not documented anywhere? I have looked at the documentation and I have not seen any mention of this anywhere.
Where else can this be used, and are there any limitations?
"[#ColumnName#]" String
Hi Michael,
I am sorry our documentation is not enough to describe our APIs now, but we are keeping update it.
And you mentioned the “[#ColumnName#]”, does that meant the column name for the data which is saved in feature’s columnValues?
InMemoryFeatureLayer layer = new InMemoryFeatureLayer();
layer.Columns.Add(new FeatureSourceColumn(“ColumnName”));
If I misunderstand please let me know.
Regards,
Don
Sorry for the delay in getting back to this, I was busy and forgot about it.And you mentioned the “[#ColumnName#]”, does that meant the column name for the data which is saved in feature’s columnValues?
Yes.
I used the string “[#ColumnName#]” to populate the Text property of a WebImage, so that it was set to the the value stored in the specified column in the FeatureSources.
What kinds of object properties can I use this with? Does this work with any string type property , or is its use limited to properties that relate directly to the HTML generated for the object?
Also, does this work for all objects, or only certain objects.
Hi Michael,
Just like you seen, InMemoryMarkerOverlay and InMemoryFeatureLayer is both work in server side, in our logic, overlay contains layers, featurelayer own its featureSource, featureSource contains many features, each feature have its own column values, you can save any value here but it have to be string.
So if you want to use it, you can only read a string, if you want to save any special type, you need write your own logic to “know” what’s its type when read then convert it.
I am sorry I have a little confused about the “object” you mentioned in your question, could you please describe your question more detail? And could you please let me know how you want to use column value for feature in your scenario?
Wish that’s helpful.
Regards,
Don
The “object” I was referring to specifically was an instance of a WebImage object belonging to a MarkerClassBreak object’s DefaultMarkerStyle property. This was used with an InMemoryMarkerOverlay. Let me post some of my code, and this might be a bit clearer.
001./// <summary>002./// Setup the AVL Overlay using an InMemoryMarkerOverlay.003./// </summary>004./// <param name=“visible”>Boolean indicating whether the Overlay is visible when the map loads.</param>005./// <param name=“visibleInOverlaySwitcher”>Boolean indicating whether the Overlay is visible in the OverlaySwitcher tool on the map.</param>006./// <returns>InMemoryMarkerOverlay for containing AVL data Markers.007.protectedInMemoryMarkerOverlay SetupAVLOverlay(boolvisible,boolvisibleInOverlaySwitcher)008.{009.stringoverlayID =“avlOverlay”;010.011.//Setup the FeatureSourceColumns.012.List<FeatureSourceColumn> columns =newList<FeatureSourceColumn>();013.014.//Add the columns to the list.015.columns.Add(newFeatureSourceColumn(“Id”));016.columns.Add(newFeatureSourceColumn(“RouteId”));017.columns.Add(newFeatureSourceColumn(“TimeStamp”));018.columns.Add(newFeatureSourceColumn(“Longitude”));019.columns.Add(newFeatureSourceColumn(“Latitude”));020.columns.Add(newFeatureSourceColumn(“Speed”));021.columns.Add(newFeatureSourceColumn(“Heading”));022.columns.Add(newFeatureSourceColumn(“Route”));023.columns.Add(newFeatureSourceColumn(“isLate”));024.025.//Create the InMemoryMarkerOverlay from the FeatureSourceColumns list.026.InMemoryMarkerOverlay avlOverlay =newInMemoryMarkerOverlay(overlayID, columns);027.028.//Setup styles.029.030.//Create the ClassBreakMarkerStyle.031.ClassBreakMarkerStyle cbms =newClassBreakMarkerStyle(“isLate”, BreakValueInclusion.IncludeValue);032.033.//Add MarkerClassBreak objects, they need to be added from smallest value to largest value.034.cbms.ClassBreaks.Add(SetupOnTimeClassBreak());//Break Value: 0035.cbms.ClassBreaks.Add(SetupLateClassBreak());//Break Value: 1036.037.//Setup the MarkerStyle on the ZoomLevels.038.avlOverlay.ZoomLevelSet.ZoomLevel01.CustomMarkerStyle = cbms;039.040.avlOverlay.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;041.042.//Apply projection to layers, the projection must be opened before this is done and should be closed afterwards.043.try044.{045.WGS84toSphMercator.Open();046.047.avlOverlay.FeatureSource.Projection = WGS84toSphMercator;048.}049.finally050.{051.WGS84toSphMercator.Close();052.}053.054.//Set visibility, and return the constructed overlay.055.avlOverlay.IsVisible = visible;056.avlOverlay.IsVisibleInOverlaySwitcher = visibleInOverlaySwitcher;057.058.returnavlOverlay;059.}060.061./// <summary>062./// Setup MarkerClassBreak for OnTime Routes. Break Value: 0063./// </summary>064./// <returns>A MarkerClassBreak object.065.protectedMarkerClassBreak SetupOnTimeClassBreak()066.{067.//Create the WebImage used for the styles.068.WebImage wi =newWebImage();069.070.//Setup the FontStyle and TextOffset.071.wi.FontStyle = DefaultFont;072.wi.TextOffsetX = 20;073.074.//Set the Text property to use the value in the FeatureSource’s Route column.075.wi.Text =“[#Route#]”;076.077.//Offset the image displayed for the marker, this places the point of the teardrop at the location.078.wi.ImageOffsetX = -10.5f;079.wi.ImageOffsetY = -25f;080.081.//Set the path for this image.082.wi.ImageVirtualPath = @"~/Content/MapIcons/AVLMarkerOnTime.gif";083.084.//Create the MarkerClassBreak with the break value.085.MarkerClassBreak mcb =newMarkerClassBreak(0);086.087.//Set the DefaultMarkerStyle’s WebImage property to our WebImage.088.mcb.DefaultMarkerStyle.WebImage = wi;089.090.//Setup the ContextMenu.091.ContextMenu menu =newContextMenu();092.093.//Setup the Schedule Maintenance ContextMenuItem and add it to the ContextMenu.094.ContextMenuItem schedMaint =newContextMenuItem();095.schedMaint.InnerHtml =“Schedule Maintenance”;096.schedMaint.OnClientClick =“openScheduleMaintenance”;097.schedMaint.CssClass =“mapMenu”;098.schedMaint.HoverCssClass =“mapMenuHover”;099.menu.MenuItems.Add(schedMaint);100.101.//Setup the Extended AVL Info ContextMenuItem and add it to the ContextMenu.102.ContextMenuItem extendAVLInfo =newContextMenuItem();103.extendAVLInfo.InnerHtml =“Info”;104.extendAVLInfo.OnClientClick =“getExtendedAVLInfo”;105.extendAVLInfo.CssClass =“mapMenuLastItem”;106.extendAVLInfo.HoverCssClass =“mapMenuHover”;107.menu.MenuItems.Add(extendAVLInfo);108.109.//Set the ContextMenu width.110.menu.Width = 150;111.112.//Set the DefaultMarkStyle.ContextMenu of the MarkerClassBreak to the ContextMenu.113.mcb.DefaultMarkerStyle.ContextMenu = menu;114.115.returnmcb;116.}117.118./// <summary>119./// Populates the maps AVL data layer.120./// </summary>121./// <param name=“map”>The ThinkGeo Map object.</param>122./// <param name=“data”>List of datapoints to populate the overlay.</param>123.protectedRectangleShape PopulateMapAVLOverlay(Map map, List<vAvlMapData> data)124.{125.RectangleShape newExtent;126.127.//Get the overlay from the map.128.InMemoryMarkerOverlay avlOverlay = (InMemoryMarkerOverlay)map.CustomOverlays[avlOverlayID];129.130.//Clear the InternalFeatures of the overlay. Note we do not need to open and close the FeatureSource when using the InternalFeatures property of the InMemoryFeatureSource.131.avlOverlay.FeatureSource.InternalFeatures.Clear();132.133.//Create features from data and add to the overlay.134.if(data !=null&& data.Count > 0)135.{136.foreach(vAvlMapData datumindata)137.{138.Dictionary<string,string> dict =newDictionary<string,string>();139.140.//AVL data.141.dict.Add(“Id”, datum.avlId.ToString());142.dict.Add(“RouteId”, datum.avlrteId.ToString());143.dict.Add(“TimeStamp”, datum.avlTimeStamp.ToString());144.dict.Add(“Longitude”, datum.avlLongitude.ToString());145.dict.Add(“Latitude”, datum.avlLatitude.ToString());146.dict.Add(“Speed”, datum.avlSpeed.ToString());147.dict.Add(“Heading”, datum.avlHeading.ToString());148.dict.Add(“Route”, datum.rteName.ToString());149.150.if(SPs.GetAVLIsLate(datum.avlrteId))151.{152.dict.Add(“isLate”,“1”);153.}154.else155.{156.dict.Add(“isLate”,“0”);157.}158.159.//Create a PointShape for the Features position.160.PointShape position = MappingUtility.PointShapeFromDBCoords(datum.avlLatitude, datum.avlLongitude);161.162.163.//Create the Feature and add it the overlay’s InternalFeatures.164.Feature newFeature =newFeature(newVertex(position), datum.avlId.ToString(), dict);165.166.avlOverlay.FeatureSource.InternalFeatures.Add(newFeature);167.}168.}169.170.//Get the bounding box for the Overlay’s Features.171.if(avlOverlay.FeatureSource.InternalFeatures.Count > 0)172.{173.try174.{175.//The FeatureSource must be opened before the GetBoundingBox method is called, and needs to be closed afterwards.176.avlOverlay.FeatureSource.Open();177.178.newExtent = avlOverlay.FeatureSource.GetBoundingBox();179.}180.finally181.{182.avlOverlay.FeatureSource.Close();183.}184.}185.else186.{187.//No data in FeatureSource, so use the projected default extent.188.newExtent = MappingUtility.GetProjectedDefaultExtent(MappingUtility.WGS84toSphMercator);189.}190.191.//Return new map extent192.returnnewExtent;193.}
You can see where I setup the Overlay, define a ClassBreakMarkerStyle, and actually populate the FeatureSource with data. The MarkerClassBreak has a property called DefaultMakerStyle, which has its own property WebImage. The WebImage has a property Text, which I presume relates directly to the markup generated for the marker. When I set the WebImage’s Text property to “[#Route#]” it takes the value from the specified column of the Feature.
If I were to extend the WebImage class, by creating a class called MyWebImage which inherited from WebImage, and added a string property “Message” to it, would I be able to simply use the statement myWebImageInstance.Message = “[#Route#]” and have it receive the value from the specified column of the Feature, or would I have to manually set it in the “set” accessor of the Message property by first parsing out the column name, lookingup the value for that column in the Feature, and then assigning the value? Something like:
publicclassMyWebImage : WebIMage{//Membersprivatestringmessage;publicstringMessage{get{returnmessage;}set{stringtemp="";//logic for getting the value from the column and assinging it to temp heremessage = temp;}}}
This was just a general question, not really related to anything particular I had planned on implementing at the moment.