Howto save to and restore from file the featurelayer's IFeatureSelection properties

1138
6
Jump to solution
06-27-2014 05:54 AM
PieterLinks
New Contributor III
Hello,

Like symbology, I would like to save to and restore from file the featurelayer's IFeatureSelection properties. This properties are set on the FeatureLayerSelectionPropertyPage.
I can do it (save to file) with the featurelayer's symbology with

IGeoFeatureLayer geoFeatureLayer = (IGeoFeatureLayer)featureLayer;

IMemoryBlobStream memoryBlobStream = new MemoryBlobStreamClass();
IObjectStream objectStream = new ObjectStreamClass();
objectStream.Stream = (IMemoryBlobStream)memoryBlobStream;
IPropertySet propertySet = new PropertySet();
IPersistStream persistStream = (IPersistStream)propertySet;

propertySet.SetProperty("
Symbology", geoFeatureLayer.Renderer);
persistStream.Save(objectStream, 0);
memoryBlobStream.SaveToFile(filePath);


but for the featureselection I can't find anything.
Does anybody know how to do it?

Many thanks,

Pieter
0 Kudos
1 Solution

Accepted Solutions
RobertMaddox
New Contributor III
Ah, sorry for misunderstanding your question, Pieter. And thank you for clearly explaining where I missed it. 😄

I can also vouch for what Neil said. I've pulled the symbology from lyr files that were generated on a different machine using datasets that don't exist on the current machine, but have the same basic structure, and it does work. (More specifically, the layers that I'm loading the symbology into are actually created by my Add-in, so I always know that they are going to have the same structure.) Check out the following code which is a modification of the code that I posted earlier (Note that featureLayer would be the IFeatureLayer that you are wanting to set the symbology for, and that the layer loaded from the file is NOT added to the map):

ILayerFile lyrFile = new LayerFile(); lyrFile.Open("mylayer.lyr"); IGeoFeatureLayer storedGeoLayer = lyrFile.Layer as IGeoFeatureLayer; IGeoFeatureLayer targetGeoLayer = featureLayer as IGeoFeatureLayer; targetGeoLayer.Renderer = storedGeoLayer.Renderer; //Force the table of contents and currently drawn map to refresh using the new symbology ArcMap.Document.UpdateContents(); ArcMap.Document.ActiveView.Refresh();


That should work without any problems, as long as the fields used for the symbology (if any) are the same in both datasets. I don't know for certain that the Selection Symbol would be stored to the lyr file, but if it is, you should probably be able to get to it by inserting the following code before the comment in the previous code:

IFeatureSelection storedSelProps = storedGeoLayer as IFeatureSelection; IFeatureSelection targetSelProps = targetGeoLayer as IFeatureSelection; targetSelProps.SelectionSymbol = storedSelProps.SelectionSymbol;


I would say that you should just try and see if it works. If it throws an error, set a breakpoint and walk through it to find where it fails. If it doesn't throw an error, but doesn't change the Selection Symbol, then I would try just loading a lyr file that was created with a custom Selection Symbol and see if it loads it back up the same way to see if it even stores it in the lyr file.

Good luck with that and let us know how it goes! 😉

View solution in original post

0 Kudos
6 Replies
RobertMaddox
New Contributor III
There's an even simpler method for saving your layer's symbology:
ILayerFile lyrFile = new LayerFile();
lyrFile.New("mylayer.lyr");
lyrFile.ReplaceContents(featureLayer);
lyrFile.Save();

Then to load it back up:
ILayerFile lyrFile = new LayerFile();
lyrFile.Open("mylayer.lyr");
IFeatureLayer featureLayer = lyrFile.Layer;
ArcMap.Document.AddLayer(featureLayer);


As for the selection set, that's not really something that has a built in method for saving. But that doesn't mean you can't create your own. The IFeatureSelection.SelectionSet is where all the OIDs of the selected features are stored. If you just save those OIDs, then you can easily retrieve them and update the IFeatureSelection.SelectionSet to contain those same OIDs when you load your layer back up. For example, add the following to the end of the above two blocks of code:

//Save selection set after saving .lyr file
IFeatureSelection featSel = featureLayer as IFeatureSelection;
IEnumIDs enumIDs = featSel.SelectionSet.IDs;
List<int> listIDs = new List<int>();
int id = enumIDs.Next();
while (id > -1)
{
    listIDs.Add(id);
    id = enumIDs.Next();
}
System.IO.File.WriteAllText("mylayer.set", string.Join(",", listIDs));


//Load selection set after loading .lyr file
IFeatureSelection featSel = featureLayer as IFeatureSelection;
ISelectionSet selSet = featSel.SelectionSet;
IEnumerable<string> strIDs = System.IO.File.ReadAllText("mylayer.set").Split(',');
int id;
foreach (string strID in strIDs)
{
    if (int.TryParse(strID, out id))
    {
        selSet.Add(id);
    }
}
featSel.SelectionChanged();


Then you'll have one file "mylayer.lyr" that contains all your symbology and stuff, and another file "mylayer.set" that contains the OIDs of your selected features. Additionally, if you want to have it all in one file and are on an NTFS partition, you can use NTFS File Streams (http://msdn.microsoft.com/en-us/library/windows/desktop/aa364404(v=vs.85).aspx) to store it in the same file by simply changing "mylayer.set" to "mylayer.lyr:selection"!

Hope that helps. 😉
0 Kudos
PieterLinks
New Contributor III
Thanks Robert for your reply.

My program reads a XML-file with the names the FeatureClasses to load (several sub-projects with the same kind of data but for multiple users on different locations). Then it creates FeatureLayers based on the FeatureClasses, with the symbology stored in binary files as described above, and, as I would like to do, also the ISymbol which is used to show the selected features (IFeaturelayer -> IFeatureSelection -> SelectionSymbol), but I don't need to store/retrieve a selectionset.

I could try to store the layer properties in a .lyr-file, but that gives a lot of overhead, and it takes time to open a .lyr-file, as it contains also a reference to the source (if the source can't be found, the symbology is invalid).

Have a nice day,

Pieter
0 Kudos
NeilClemmons
Regular Contributor III
Thanks Robert for your reply.

I could try to store the layer properties in a .lyr-file, but that gives a lot of overhead, and it takes time to open a .lyr-file, as it contains also a reference to the source (if the source can't be found, the symbology is invalid).


We have about a dozen applications that add layers to the map for storing program output.  Each of these layers gets its symbology from a layer file that installs with the app.  Opening the layer file takes very little time and the symbology is not invalid.  You simply get the layer from the file, use IObjectCopy to clone its renderer and assign that renderer to the layer.  The code below is for a raster layer but it can be modified to work for a feature layer:

            Dim layerFile As ILayerFile = New LayerFile
            layerFile.Open(layerFilePath)
            Dim templateLayer As ILayer = layerFile.Layer()

            Dim objectCopy As IObjectCopy = New ObjectCopy
            Dim renderer As IRasterRenderer = DirectCast(objectCopy.Copy(DirectCast(templateLayer, IRasterLayer).Renderer), IRasterRenderer)
            rasterLayer.Renderer = renderer


This will work as long as the renderer properties are valid for the layer you're assigning it to (i.e. field names match, etc.).  While I haven't specifically tried it, it should be possible to copy the layer's selection settings as these settings are part of the serialized layer object stored in the layer file.
0 Kudos
RobertMaddox
New Contributor III
Ah, sorry for misunderstanding your question, Pieter. And thank you for clearly explaining where I missed it. 😄

I can also vouch for what Neil said. I've pulled the symbology from lyr files that were generated on a different machine using datasets that don't exist on the current machine, but have the same basic structure, and it does work. (More specifically, the layers that I'm loading the symbology into are actually created by my Add-in, so I always know that they are going to have the same structure.) Check out the following code which is a modification of the code that I posted earlier (Note that featureLayer would be the IFeatureLayer that you are wanting to set the symbology for, and that the layer loaded from the file is NOT added to the map):

ILayerFile lyrFile = new LayerFile(); lyrFile.Open("mylayer.lyr"); IGeoFeatureLayer storedGeoLayer = lyrFile.Layer as IGeoFeatureLayer; IGeoFeatureLayer targetGeoLayer = featureLayer as IGeoFeatureLayer; targetGeoLayer.Renderer = storedGeoLayer.Renderer; //Force the table of contents and currently drawn map to refresh using the new symbology ArcMap.Document.UpdateContents(); ArcMap.Document.ActiveView.Refresh();


That should work without any problems, as long as the fields used for the symbology (if any) are the same in both datasets. I don't know for certain that the Selection Symbol would be stored to the lyr file, but if it is, you should probably be able to get to it by inserting the following code before the comment in the previous code:

IFeatureSelection storedSelProps = storedGeoLayer as IFeatureSelection; IFeatureSelection targetSelProps = targetGeoLayer as IFeatureSelection; targetSelProps.SelectionSymbol = storedSelProps.SelectionSymbol;


I would say that you should just try and see if it works. If it throws an error, set a breakpoint and walk through it to find where it fails. If it doesn't throw an error, but doesn't change the Selection Symbol, then I would try just loading a lyr file that was created with a custom Selection Symbol and see if it loads it back up the same way to see if it even stores it in the lyr file.

Good luck with that and let us know how it goes! 😉
0 Kudos
PieterLinks
New Contributor III
Thanks Robby and Neil.
I have now this code:

private IFeatureLayer FeatureLayerFromFeatureClass(IFeatureClass featureClass, string layername)
{
    IFeatureLayer featureLayer = new FeatureLayerClass();
    featureLayer.Name = layerName;
    featureLayer.FeatureClass = featureClass;
    IFeatureSelection featureSelection = featureLayer as IFeatureSelection;

    if (File.Exists(_layerFilePath))
    { 
        // open the layer from the .lyr-file
        ILayerFile layerFile = new LayerFileClass();
        layerFile.Open(_layerFilePath);
        IGeoFeatureLayer sourceGeoFeatureLayer = layerFile.Layer as IGeoFeatureLayer;

        // destination
        IGeoFeatureLayer destinationGeoFeatureLayer = featureLayer as IGeoFeatureLayer;
        
        // copier
        IObjectCopy objectCopy = new ObjectCopyClass();

        // get the symbology
        IFeatureRenderer featureRenderer = objectCopy.Copy(sourceGeoFeatureLayer.Renderer) as IFeatureRenderer;
        destinationGeoFeatureLayer.Renderer = featureRenderer;

        // get the feature selectionsymbol
        IFeatureSelection sourceFeatureSelection = sourceGeoFeatureLayer as IFeatureSelection;
        featureSelection.SelectionSymbol = objectCopy.Copy(sourceFeatureSelection.SelectionSymbol) as ISymbol;
        featureSelection.SetSelectionSymbol = true;

        // close nicely
        layerFile.Close();
    }
    return featureLayer;
}


    and it retrieves the symbology but not the selectionsymbol.
{edited} I adapted the .lyr-files in ArcCatalog and selected a custom symbol, but when I open the FeatureLayerSelectionPropertyPage in the program it is the default symbol, what I don't want. {/edited}
0 Kudos
PieterLinks
New Contributor III
After reviewing the code, I've found an overseen piece that did reset the selectionsymbol.
Thus, the above code works for both featurerenderer and selectionsymbol.
Many thank for your help!
0 Kudos