7 votos

¿Detectar cambios en el índice de contenidos en ArcMap mediante ArcObjects?

¿Cuál es el método preferido y/o más eficiente para detectar un cambio en la tabla de contenidos en ArcMap utilizando ArcObjects? Mi implementación actual se basa en un diccionario con los nombres e índices de las capas.

public static Dictionary<string, int> layerEnumerator()
{
    IEnumLayer enumLayer = ArcMap.Document.FocusMap.get_Layers(null, false);
    enumLayer.Reset();
    ILayer layer = enumLayer.Next();
    Dictionary<string, int> layerDictionary = new Dictionary<string, int>();
    int lyrNdx = 0;
    while (!(layer == null))
    {
        if (!(layerDictionary.ContainsKey(layer.Name)))
        {
          layerDictionary.Add(layer.Name, lyrNdx);
        }
        lyrNdx++;
        layer = enumLayer.Next();
    }

        return layerDictionary;
    }

Por lo general, llamo a esto cuando necesito encontrar la posición de una capa específica en la TdC. ¿Existe un medio más eficiente para recoger lo que hay en la TdC en un momento dado (como un evento para el Contenido de la TdC Cambiado)? La solución que he proporcionado arriba parece inadecuada e ineficiente en el mejor de los casos.

7voto

lepole Puntos 1588

Puedes utilizar el manejador IActiveViewEvents para determinar cuándo se añade o elimina un elemento de la TOC. En este ejemplo clsPropSet.Document es una ref. IMxDocument y clsPropSet.Map es una ref. IMap.

    private static IDocumentEvents_CloseDocumentEventHandler cdHandler;
    private static IActiveViewEvents_ItemAddedEventHandler iaHandler;
    private static IActiveViewEvents_ItemDeletedEventHandler idHandler;

    internal void SetupEvents()
    {
        //HANDLE THE FOLLOWING EVENTS
        cdHandler = new IDocumentEvents_CloseDocumentEventHandler(OnDocClose);
        ((IDocumentEvents_Event)clsPropSet.Document).CloseDocument += cdHandler;
        iaHandler = new IActiveViewEvents_ItemAddedEventHandler(OnActiveViewEventsItemAdded);
        ((IActiveViewEvents_Event)clsPropSet.Map).ItemAdded += iaHandler;
        idHandler = new IActiveViewEvents_ItemDeletedEventHandler(OnActiveViewEventsItemDeleted);
        ((IActiveViewEvents_Event)clsPropSet.Map).ItemDeleted += idHandler;
    }

    internal void UnloadEvents()
    {
        ((IDocumentEvents_Event)clsPropSet.Document).CloseDocument -= cdHandler;
        ((IActiveViewEvents_Event)clsPropSet.Map).ItemAdded -= iaHandler;
        ((IActiveViewEvents_Event)clsPropSet.Map).ItemDeleted -= idHandler;
    }

    private void OnDocClose()
    {
        //DO SOMETHING WHEN DOCUMENT CLOSES
    }

    private void OnActiveViewEventsItemAdded(object Item)
    {
        //DO SOMETHING WHEN ITEM ADDED
    }

    private void OnActiveViewEventsItemDeleted(object Item)
    {
        //DO SOMETHING WHEN ITEM REMOVED
    }

0 votos

Este fragmento de fuente es realmente útil para implementar lo que necesito hacer. Voy a aceptar la respuesta de @blah238 ya que parece capturar la solución en un sentido más generalizado.

0 votos

Qué bien. Me imaginé que encontrarías el evento ContentsChanged si buscabas en la documentación de IActiveViewEvents. Acabo de copiar/pegar lo anterior de una de mis soluciones. En este caso sólo estaba pendiente de los elementos que se añadían o eliminaban.

5voto

auramo Puntos 161

Hay un número de eventos a los que puede suscribirse para hacer algo cuando el contenido del mapa cambia, se añaden, reordenan o eliminan elementos, la colección de mapas cambia, el documento del mapa se abre, se guarda o se cierra, etc.

Una cosa que me hizo tropezar fue cuando estaba tratando de determinar cuándo cambia la fuente de datos de una clase de característica broken-data-source lo que me llevó a utilizar IActiveViewEvents.ContentsChanged como un cajón de sastre de propósito general. Le dirá cuando algo cambios, sólo que no qué cambiado. No estoy seguro de si captará cuando se añadan, eliminen o reordenen cosas en la TOC, ya que hay eventos explícitos para ello, así que asegúrate de probarlo.

Dependiendo de lo que estés tratando de hacer y si necesitas hacer un seguimiento de ciertas cosas, podrías continuar usando un diccionario y simplemente actualizarlo/ejecutar tu lógica cada vez que esos eventos se disparen. Yo consideraría el uso de un objeto de capa HashCode como clave en lugar de Name aunque desde Name no se garantiza que sea único y, de hecho, es susceptible de ser modificado por el usuario. Lamentablemente, ArcObjects no proporciona un identificador de capa único y persistente (al menos en el escritorio, creo que en el lado del servidor sí), por lo que HashCode es lo mejor que puedes hacer.

Tendrá que cablear múltiples eventos, empezando por los eventos Open/NewDocument en los que cableará su(s) manejador(es) de eventos de vista activa -- uno para el FocusMap y otro para el PageLayout, ya que reciben eventos diferentes -- ya que cada vez que se cambie el documento actual o el marco de datos activo, los manejadores de eventos de vista activa existentes quedarán invalidados. Para estar seguro, añada uno para CloseDocument donde desconecte los manejadores de eventos de la vista activa.

Compruebe las muestras para ver ejemplos de esto, ya que puede ser complicado hacerlo bien.

0 votos

Genial, gracias. Probablemente voy a mantener mi método existente para agarrar la capa por un identificador (probablemente cambiando a la HashCode), pero ser capaz de disparar esto en un evento más controlado como este es definitivamente lo que necesitaba.

1 votos

NO utilice el código hash de un objeto como identificador. No hay garantía de que el GetHashCode de dos objetos diferentes devuelva valores diferentes.

0 votos

Mejor que el nombre, ¿qué otra cosa sugeriría? ¿Una combinación de propiedades? También nunca he tenido una colisión cuando se utiliza con los objetos de la capa.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X