I was wondering if there is a way I can code the TOC control so that I can select multiple layers and GROUP them together. So if i uncheck the group, all layers will be unchecked and be invisible.
Thanks and Regards,
Kevin
arcgis-10.0arcgis-engine
I was wondering if there is a way I can code the TOC control so that I can select multiple layers and GROUP them together. So if i uncheck the group, all layers will be unchecked and be invisible.
Thanks and Regards,
Kevin
Not as visually cool but at least it work, use the MoveLayerEx in IMapLayers can be used to move a layer in a group layer, use the same grouplayer as source and target and apply the index that the layer shall have in the group. Made a small code sample:
Private Sub MoveGroupLayerItem(ByVal up As Boolean)
Dim layer As ILayer = getLayer()
Dim layerIndex As Integer = getLayerGroupIndex()
Dim map As IMap = axMapControl1.ActiveView.FocusMap
Dim mapLayers As IMapLayers = CType(map, IMapLayers)
Dim groupLayer As IGroupLayer = CType(map.Layer(0), IGroupLayer)
Dim compLayer As ICompositeLayer = CType(groupLayer, ICompositeLayer)
If up Then
If layerIndex > 0 Then
mapLayers.MoveLayerEx(groupLayer, groupLayer, layer, layerIndex - 1)
End If
Else
If (layerIndex < compLayer.Count - 1) Then
mapLayers.MoveLayerEx(groupLayer, groupLayer, layer, layerIndex + 1)
End If
End If
axMapControl1.Refresh(esriViewDrawPhase.esriViewAll, Nothing, Nothing)
End Sub
Feature classes and object classes do have their ids, which are unique within a single geodatabase. This very often satisfies most scenarios similar to yours.
If you cannot uniquely identify a layer based on its feature class, you can leverage layer extensions to store arbitrary data with the layer.
A layer extension can be added to a layer via ILayerExtensions interface. Now, there is no common interface for layer extensions, but they typically implement some persistence through IPersistStream. Your layer extension would not do anything special but store some data by which you will uniquely identify your added layer.
So your task would be as follows:
I had a very similar problem and layers extensions turned out to be the best fit.
EDIT: below I post some code for a helper static class which allows you to quickly work with properties set inside a propertyset stored in the layer extension (.NET 3.5 or higher required). It takes care of accessing the extension object and creating it if not already assigned to the layer. It's used like this:
// 1) is a particular property ("MY.KEY") set on a layer?
var isPropertySet = PropertySetLayerExtensionHelper.ExtensionPropertySetContainsKey(layer, "MY.KEY");
// 2) set a property with a value on the layer:
PropertySetLayerExtensionHelper.ExtensionPropertySetSetValueForKey(layer, "MY.KEY", "SomeValue");
// 3) retrieve a value for the given key stored at some point before:
var value = PropertySetLayerExtensionHelper.ExtensionPropertySetGetValueForKey(layer, "MY.KEY");
Instead of "SomeValue" you will probably generate and store some kind of layer identifier in there.
Here's the full source code for the PropertySetLayerExtensionHelper
class:
public static class PropertySetLayerExtensionHelper
{
/// <summary>
/// Returns whether the property set stored in the layer extensions contains a value for the given key.
/// </summary>
/// <param name="layer">The layer.</param>
/// <param name="key">The key.</param>
/// <returns>Whether the property set stored in the layer extensions contains a value for the given key.</returns>
public static bool ExtensionPropertySetContainsKey(ILayer layer, string key)
{
if (layer == null) throw new ArgumentNullException("layer");
if (key == null) throw new ArgumentNullException("key");
var propertySet = GetPropertySetInLayerExtension(layer);
return propertySet != null
&& propertySet.AsEnumerable().Any(pair => pair.Key.Equals(key, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// Returns the value for the given key from the property set stored in the layer extension or <b>null</b>
/// if no such key is present.
/// </summary>
/// <param name="layer">The layer.</param>
/// <param name="key">The key.</param>
/// <returns>The value for the given key from the property set stored in the layer extension or <b>null</b>
/// if no such key is present.</returns>
public static object ExtensionPropertySetGetValueForKey(ILayer layer, string key)
{
if (layer == null) throw new ArgumentNullException("layer");
if (key == null) throw new ArgumentNullException("key");
var propertySet = GetPropertySetInLayerExtension(layer);
if (propertySet == null) return null;
return propertySet.AsEnumerable()
.Where(p => p.Key.Equals(key, StringComparison.OrdinalIgnoreCase))
.Select(p => p.Value)
.FirstOrDefault();
}
/// <summary>
/// Sets the value for the given key in the property set stored in a layer extension. If there is
/// no property set among the layer's extensions, it is created and assigned to the layer.
/// </summary>
/// <param name="layer">The layer.</param>
/// <param name="key">The key.</param>
/// <param name="value">The value for the given key.</param>
public static void ExtensionPropertySetSetValueForKey(ILayer layer, string key, object value)
{
if (layer == null) throw new ArgumentNullException("layer");
if (key == null) throw new ArgumentNullException("key");
var propertySet = GetOrCreatePropertySetInLayerExtension(layer);
if (propertySet == null)
{
throw new InvalidOperationException("The given layer does not support layer extensions.");
}
propertySet.SetProperty(key, value);
}
/// <summary>
/// Returns a property set from a layer extension.
/// </summary>
/// <param name="layer">The layer.</param>
/// <returns>A property set from a layer extension.</returns>
public static IPropertySet GetPropertySetInLayerExtension(ILayer layer)
{
if (layer == null) throw new ArgumentNullException("layer");
var layerExtensions = layer as ILayerExtensions;
if (layerExtensions == null)
{
return null;
}
var propertySetExtension = layerExtensions.AsEnumerable().OfType<IPropertySet>().FirstOrDefault();
return propertySetExtension;
}
/// <summary>
/// Returns a property set from a layer extension. If not set on the layer,
/// the property set is created and assigned to it.
/// </summary>
/// <param name="layer">The layer.</param>
/// <returns>A property set from a layer extension.</returns>
public static IPropertySet GetOrCreatePropertySetInLayerExtension(ILayer layer)
{
if (layer == null) throw new ArgumentNullException("layer");
var propertySet = GetPropertySetInLayerExtension(layer);
if (propertySet != null)
{
return propertySet;
}
var layerExtensions = layer as ILayerExtensions;
if (layerExtensions == null)
{
return null;
}
propertySet = new PropertySetClass();
layerExtensions.AddExtension(propertySet);
return propertySet;
}
private static IEnumerable<object> AsEnumerable(this ILayerExtensions layerExtensions)
{
if (layerExtensions == null) throw new ArgumentNullException("layerExtensions");
for (var i = 0; i < layerExtensions.ExtensionCount; i++)
{
yield return layerExtensions.get_Extension(i);
}
}
private static IEnumerable<KeyValuePair<string, object>> AsEnumerable(this IPropertySet propertySet)
{
if (propertySet == null) throw new ArgumentNullException("propertySet");
if (propertySet.Count == 0) yield break;
object names;
object values;
propertySet.GetAllProperties(out names, out values);
var nameArray = (string[])names;
var valueArray = (object[])values;
for (var i = 0; i < nameArray.Length; i++)
{
yield return new KeyValuePair<string, object>(nameArray[i], valueArray[i]);
}
}
}
Best Answer
You probably need to do some coding, because I haven't seen anything similar to the ArcMap Group context menuitem in engine.
But you should be able to do this with a group layer.
One way would be to create a group layer and add the layers in the group layer instead of the map and add the group layer to the map. Don't forget to fire the ContentsChanged() on the Active View otherwise the Toc will not be refreshed and PartialRefresh(esriViewAll,Nothing,Nothing) to update the map.
An other way would be to move the layers to the newly created group layer, see the question rearrange layers. To find out the layers that get clicked you need to use the HitTest, check out the context menu sample on how to use hit testing.