How to access sublayer of a basemap in arcobjects? - arcobjects

ILayer layer = mapControl.get_Layer(1); //layer 1 is usa_base_map
I have an ILayer, now I want to access and turn on and off various sublayers like the street layer or the railroad layer. Can you tell me how to access these layers?

I think you'll want to cast your group layer to an ICompositeLayer (linky).

Accessing a basemap sublayer
The following code example shows how to access a basemap sublayer, retrieve the inner layer, update a property on the inner layer, and notify the basemap layer of the change. The notification invalidates the layer's internal cache so that the content is redrawn to reflect the update. In this example, the update clears the definition expression of a feature layer.
[C#]
private void UpdateBasemapSublayerAndNotify(IBasemapLayer basemapLayer, IMap map)
{
ICompositeLayer basemapCompositeLayer = basemapLayer as ICompositeLayer;
IBasemapSubLayer basemapSubLayer = basemapCompositeLayer.get_Layer(0)as
IBasemapSubLayer;
ILayer innerLayer = basemapSubLayer.Layer;
IFeatureLayer featureLayer = innerLayer as IFeatureLayer;
if (featureLayer != null)
{
IFeatureLayerDefinition featureLayerDef = featureLayer as
IFeatureLayerDefinition;
featureLayerDef.DefinitionExpression = "";
}
//When performing operations against the wrapped layer that change properties, you must
//notify the basemaplayer so the display cache can be recreated if necessary.
basemapLayer.NotifyLayerChanged(basemapSubLayer as ILayer,
esriLayerEventHint.esriLayerEventHintProperties, null);
IActiveView activeView = map as IActiveView;
activeView.PartialRefresh(esriViewDrawPhase.esriViewGeography, basemapLayer as
object, null);
}
[VB.NET]
Private Sub UpdateBasemapSublayerAndNotify(ByVal basemapLayer As IBasemapLayer, ByVal map As IMap)
Dim basemapCompositeLayer As ICompositeLayer = TryCast(basemapLayer, ICompositeLayer)
Dim basemapSubLayer As IBasemapSubLayer = TryCast(basemapCompositeLayer.get_Layer(0), IBasemapSubLayer)
Dim innerLayer As ILayer = basemapSubLayer.Layer
Dim featureLayer As IFeatureLayer = TryCast(innerLayer, IFeatureLayer)
If featureLayer IsNot Nothing Then
Dim featureLayerDef As IFeatureLayerDefinition = TryCast(featureLayer, IFeatureLayerDefinition)
featureLayerDef.DefinitionExpression = ""
End If
'When performing operations against the wrapped layer that change properties, you must
'notify the basemaplayer so the display cache can be recreated if necessary.
basemapLayer.NotifyLayerChanged(TryCast(basemapSubLayer, ILayer), esriLayerEventHint.esriLayerEventHintProperties, Nothing)
Dim activeView As IActiveView = TryCast(map, IActiveView)
activeView.PartialRefresh(esriViewDrawPhase.esriViewGeography, TryCast(basemapLayer, Object), Nothing)
End Sub

Related

Unity how to Create Texts via script?

I'm trying to create Texts via script. I want to create texts with the name of objects of a certain tag.
"For example, if I have two objects named Cube and Sphere and both have a tag of "TargetObj" then their names should be displayed as texts on the screen(in the case Cube, Sphere)"
I want to achieve this regardless of the number of objects. so a loop is needed.
Here is what I've tried so far.
[SerializeField] GameObject LevelCanvas;
targetObjects = GameObject.FindGameObjectsWithTag("TargetObj");
foreach (var obj in targetObjects)
{
Text mytext = LevelCanvas.AddComponent<Text>();
mytext.text = "Find " + obj.name;
Font ArialFont = (Font)Resources.GetBuiltinResource(typeof(Font), "Arial.ttf");
mytext.font = ArialFont;
mytext.material = ArialFont.material;
}
it only shows one object name although I have 2 more objects that were supposed to be shown as well.
You need to create a text object on a new gameobject.
static Text CreateText(Transform parent)
{
var go = new GameObject();
go.transform.parent = parent;
var text = go.AddComponent<Text>();
return text;
}
var mytext = CreateText(LevelCanvas.transform);
myext.text = ...
Many components in unity can only be added once per game object. That means you need a separate game object for every text you want to show.
A typical way to approach this is to create a "prefab" of a game object which has a text element already. This way you can set a default font and other settings.
Then in code you use the Instantiate method on that prefab and via GetComponent() you can access the text component instance to set the desired string to display.

How to assign TextAssets to a scene gameobject via editor script?

I have a scene with levels. This scene has 1.000 levels. Its level has a TextAsset. I would like to run an EditorScript and assign those TextAssets via script and not by Dragging and dropping 1.000 TextAssets to the scene. Then save the scene automatically.
Scene mainScene = SceneManager.GetSceneByName("Main");
GameObject[] gameObjects = mainScene.GetRootGameObjects();
GameManager gameManager = gameObjects[0].GetComponent<GameManager>();
List<LanguageCategory> languageCategories = new List<LanguageCategory>();
LanguageCategoryPackInfo l1 = new LanguageCategoryPackInfo();
l1.displayName = "t1";
LanguageCategoryPackInfo l2 = new LanguageCategoryPackInfo();
l2.displayName = "t2";
languageCategories.Add(l1);
languageCategories.Add(l2);
gameManager.LanguageCategoryPackInfos = languageCategories;
//do the same assignment again, but with no luck
mainScene.GetRootGameObjects()[0].GetComponent<GameManager>().LanguageCategoryPackInfos = languageCategories;
EditorSceneManager.SaveScene(mainScene);
After running the above code the scene doesn't seems to be changed.
The problem with directly making some changes in the component doesn't mark it as dirty and thus changes are not saved! (see also explenation in SerializedObject and solution below.)
You can do this manually using EditorUtility.SetDirty. As noted there you should always combine it with first also calling Undo.RecordObject.
If you don't care about the Undo/Redo functionality you can also simply use EditorSceneManager.MarkSceneDirty
Scene mainScene = SceneManager.GetSceneByName("Main");
GameObject[] gameObjects = mainScene.GetRootGameObjects();
GameManager gameManager = gameObjects[0].GetComponent<GameManager>();
List<LanguageCategory> languageCategories = new List<LanguageCategory>();
LanguageCategoryPackInfo l1 = new LanguageCategoryPackInfo();
l1.displayName = "t1";
LanguageCategoryPackInfo l2 = new LanguageCategoryPackInfo();
l2.displayName = "t2";
languageCategories.Add(l1);
languageCategories.Add(l2);
// record an undo point
Undo.RecordObject(gameManager, "languages added");
gameManager.LanguageCategoryPackInfos = languageCategories;
// mark the object dirty so it will be saved
EditorUtility.SetDirty(gameManager);
// or simply directly
EditorSceneManager.MarkSceneDirty();
EditorSceneManager.SaveScene(mainScene);
As alternative though it is more complex it is always recommended to instead go through the SerializedObject and SerializedPropertys which handles all the marking dirty and undo/redo functionalities for you automatically.
Scene mainScene = SceneManager.GetSceneByName("Main");
GameObject[] gameObjects = mainScene.GetRootGameObjects();
GameManager gameManager = gameObjects[0].GetComponent<GameManager>();
SerializedObject serializedObject = new SerializedObject(gameManager);
SerializedProperty languageCategories = serializedObject.FindProperty("LanguageCategoryPackInfos");
// load the current real values into the serializedObject
serializedObject.Update();
languageCategories.arraySize = 2;
SerializedProperty l1 = languageCategories.GetArrayElementAtIndex(0);
l1.FindPropertyRelative("displayName").stringValue = "t1";
SerializedProperty l2 = languageCategories.GetArrayElementAtIndex(1);
l2.FindPropertyRelative("displayName").stringValue= "t2";
// writes the changes bakc to the actual properties and marks them as dirty etc
serializedObject.ApplyModifiedProperties();
EditorSceneManager.SaveScene(mainScene);
Note: Typed on smartphone so no warrenty, but I hope the idea gets clear

After making a layer visible, map.getCanvas() does not contain the layer immediately. mapbox-gl-js

I am trying to set some layers' layout visible property to 'visible' using the 'setLayoutProperty' method in mapbox-gl-js.
this.toggleCanvasMarkersVisibility(true); // This code sets visibility to visible
// Create a snapshot of the map as follows:
this.map.getCanvas().toBlob(function (blob) {
canvasContext.strokeStyle = '#CCCCCC';
canvasContext.strokeRect(leftPosition, topPosition, width, height);
var img = new Image();
img.setAttribute("crossOrigin", "anonymous");
var srcURL = URL.createObjectURL(blob);
img.onload = function () {
canvasContext.drawImage(img, leftPosition, topPosition, width, height);
// Other operations
});
The layers which I just set to 'visible' are not visible yet on the map. How do I detect if they are visible other than the visible property, because the 'visible' property is set to 'visible'?
The PNG as a result does not consist of the markers.
Any help is appreciated!

How can I add more than custom control using code behind?

Here I create two objects form my Custom control and add them to the form but it show the first one only, why ?
private void frmWelcome_Load(object sender, EventArgs e)
{
// Count number of Contacts in XML
XmlDocument doc = new XmlDocument();
doc.Load(#"C:\Users\Taha\Documents\Visual Studio 2013\Projects\ContactsMangementSystem\ContactsMangementSystem\ContactsData.xml");
int numOfContacts = doc.GetElementsByTagName("Contact").Count;
XmlNodeList nodelist = doc.GetElementsByTagName("Contact");
foreach (XmlNode item in nodelist)
{
// Create Control for each Item
ContactControl.ContactControl userControl = new ContactControl.ContactControl();
// Fill Control With Data
userControl.labelOrganizationText = item.ChildNodes.Item(5).InnerText;
userControl.labelTitleText = item.ChildNodes.Item(0).InnerText;
userControl.labelWorkAddressText = item.ChildNodes.Item(12).InnerText;
userControl.labelWorkPhoneText = item.ChildNodes.Item(8).InnerText;
userControl.labelEmailText = item.ChildNodes.Item(7).InnerText;
Image img = Image.FromFile(item.ChildNodes.Item(9).InnerText);
userControl.ContactImage = img;
// Add item to the form
this.Controls.Add(userControl);
}
ContactControl.ContactControl userControl2 = new ContactControl.ContactControl();
this.Controls.Add(userControl2);
}
If you add controls all by yourself, aka programmaticaly, to the Control collection of a form, you become responsible for handling the position, bounds, size etc. I'll demonstrate the root cause of your issue with a trimmed down code example that is similar to yours.
First I create a UserControl, with one label on it. Set the label property Dock to Fill, Font to Point 28, TextAlign to MiddelCentre and most important Modifiers to Public:
Now we create a new Form in the Designer and add a Timer, a Button, two checkboxes and a FlowLayoutPanel to it. The FlowLayoutPanel has its Anchor property set to Top,Left,Right,Bottom so it will resize if the form resizes. Our design looks like this:
In the Timer_Tick event a new instance of the UserControl is created and either added to the Forms Control collection or the FlowLayoutPanel. There are two variables that keep track of the number of controls created and on which position the control needs to be.
Here is the code in the codebehind of the form:
int position = 0; // what position the control should be
int controlsCreated = 0; // how many controls did we create
private void timer1_Tick(object sender, EventArgs e)
{
// create the control
var ucnext = new UserControl1();
controlsCreated++;
ucnext.label1.Text = controlsCreated.ToString();
// where are we adding the control?
if (!chkFlow.Checked)
{
// do we want to use the Location?
// if not Top will be 0
if (chkLocation.Checked)
{
// Ok, position times height should gives us
// a free spot
ucnext.Top = position * ucnext.Height;
position++;
}
this.Controls.Add(ucnext);
ucnext.BringToFront(); // otherwise we always see control 1
} else
{
// now the FlowLayout takes over all Layout logic
this.flowLayoutPanel1.Controls.Add(ucnext);
}
}
private void button1_Click(object sender, EventArgs e)
{
this.timer1.Enabled = !this.timer1.Enabled;
this.btnStart.Text = this.timer1.Enabled ? "Pause" : "Continue";
}
If we run this we can check and uncheck the options for Location and Adding to the flowlayout to see the various effects of adding controls to either the form directly or the FlowLayout panel.
So keep in mind if you add a control yourself to the Control collection of a Form make sure to set its Location properties (Top, Left) to a suitable value. If you do this wrong your control is going to end up hidden behind another control or is placed outside the visible bounds of the form. If you don't know before hand how many controls you will have consider using one of the container controls, like a FlowLayoutPanel.

Bing maps polygon/polyline appears beneath image overlay

I´ve been following this post about using an image overlay for bing maps:
http://blogs.msdn.com/b/bingdevcenter/archive/2014/04/04/image-overlays-with-bing-maps-native.aspx
What I want to now is to be able to add polygons/polylines on top of this image. Lets say for example that we use the following code:
(From here: http://blogs.bing.com/maps/2014/01/23/make-clickable-shapes-in-the-native-bing-maps-control/)
private void MyMapLoaded(object sender, RoutedEventArgs e)
{
//Add a shape layer to the map
shapeLayer = new MapShapeLayer();
MyMap.ShapeLayers.Add(shapeLayer);
//Create mock data points
var locs = new LocationCollection();
locs.Add(new Location(coordinates that are over the image));
locs.Add(new Location(coordinates that are over the image));
locs.Add(new Location(coordinates that are over the image));
//Create test polygon
var polygon = new MapPolygon();
polygon.Locations = locs;
polygon.FillColor = Colors.Red;
shapeLayer.Shapes.Add(polygon);
var locs2 = new LocationCollection();
locs2.Add(new Location(20, 20));
locs2.Add(new Location(40, 40));
locs2.Add(new Location(50, 20));
//Create test polyline
var polyline = new MapPolyline();
polyline.Locations = locs2;
polyline.Width = 5;
polyline.Color = Colors.Blue;
//Add the shape to the map
shapeLayer.Shapes.Add(polyline);
}
The problem is that the polygon/polyline will always appear beneath the image.
ShapeLayer has a property for z-index but it does not help. Is there a way for my polygons to always be on top?
Not sure why you want to do this, but you won't be able to show a MapPolygon above a user control that is added as a child of the map. That said, you can create WPF Polygons and added them. What you could do is create a custom user control that combines the image overlay functionality with something like this: http://blogs.msdn.com/b/bingdevcenter/archive/2014/03/25/custom-shapes-in-windows-store-apps-c.aspx