1

I've been working on this for a little while now, and can not seem to get this thing working.

I've managed to export a geodatabase feature class and shapefile to a shapefile, but what I'm struggling with right now is writing an in-memory feature layer (one that is created based on a selection of features) to a shapefile/geodatabase.

If anyone can help me with a code snippet (doesn't matter the language), or some links to some dark corner of the ESRI docs, I would be much obliged.

UPDATE

I used the following code to create the IFeatureLayer:

IFeatureSelection featureSelection = (IFeatureSelection)layer;
if (featureSelection.SelectionSet.Count > 0)
{
    IFeatureLayerDefinition2 featDef = (IFeatureLayerDefinition2)featureSelection;
    IFeatureLayer fLayer = featDef.CreateSelectionLayer(
        String.Format( CultureInfo.InvariantCulture,
            "{0}_Selection", layer.Name ),
        true, "", "" );

    featureSelection.Clear();

    if (fLayer != null)
    {
        _hook.FocusMap.AddLayer( fLayer );
        _hook.ActiveView.Refresh();
    }
}

This creates and adds a new layer to the TOC.

What I'm missing now is taking that Feature selection and saving this to a Shapefile (for now).

The code example I've been working with is from esri code snippets but I'm getting stuck on the following:

IDataset sourceDataset = (IDataset)_layer;

IWorkspace sourceWorkspace;
IPropertySet propertySet = sourceDataset.Workspace.ConnectionProperties;
sourceWorkspace = sourceDataset.Workspace.WorkspaceFactory.Open( propertySet, 0 );

if (sourceDataset.FullName != null)
{
    // HERE - Invalid Cast Exception.
    IWorkspaceName sourceWorkspaceName = (IWorkspaceName)sourceDataset.FullName;
}

The full exception is here:

Unable to cast COM object of type 'System.__ComObject' to interface type 'ESRI.ArcGIS.Geodatabase.IWorkspaceName'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{FADD975C-E36F-11D1-AA81-00C04FA33A15}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

I guess the exception is thrown because the FullName property though is not empty is not compatible because of the type of COM object it is wrapping.

Any thoughts?

8
  • 1
    Are you looking to avoid using the geoprocessor? You could use FeatureClassToFeatureClass and it should be able to handle the in-memory feature layer.
    – blah238
    Commented May 23, 2012 at 21:26
  • 2
    Try code from here. Commented May 23, 2012 at 21:31
  • @blah238 I am trying to avoid the geoprocessor, though the reasons are for doing so are pride and spite. Commented May 23, 2012 at 22:14
  • @KirkKuykendall I might be able to make that work, I'll give it a go tomorrow morning and update the question with the code. Thanks Commented May 23, 2012 at 22:15
  • 2
    To get the workspacename of a featurelayer's data source, I would do this: cast IFeatureLayer.Featureclass as IDataset, then cast the dataset.FullName as IDatasetName, then get IDatasetName.WorkspaceName. Commented May 24, 2012 at 17:43

1 Answer 1

2

Ok Folk, This took some time to get worked out, mainly because it is a part of the ArcObjects API that I haven't worked with often, or frustration clouding pragmatic thought, or an extremely large (misleading) API. I would like to thank Kirk Kuykendall for some additional resources and ideas on this and other sites.

Here is the solution. It has been lightly tested but its there for all.

public static bool ExportLayerToShapefile(
        string shapePath, 
        string shapeName, 
        ILayer source,
        out IEnumFieldError fieldErrors,
        out IEnumInvalidObject invalidObjects)
{
    IGeoFeatureLayer sourceFeatLayer = (IGeoFeatureLayer)source;
    IFeatureLayer sfeatlayer = (IFeatureLayer)sourceFeatLayer;
    IFeatureClass sfeatClass = sfeatlayer.FeatureClass;
    IDataset sdataset = (IDataset)sfeatClass;
    IDatasetName sdatasetName = (IDatasetName)sdataset.FullName;

    ISelectionSet sSelectionSet = (
        (ITable)source).Select( new QueryFilter(),
        esriSelectionType.esriSelectionTypeHybrid,
        esriSelectionOption.esriSelectionOptionNormal,
        sdataset.Workspace );

    IWorkspaceFactory factory;
    factory = new ShapefileWorkspaceFactory();
    IWorkspace targetWorkspace = factory.OpenFromFile( shapePath, 0 );
    IDataset targetDataset = (IDataset)targetWorkspace;

    IName targetWorkspaceName = targetDataset.FullName;
    IWorkspaceName tWorkspaceName = (IWorkspaceName)targetWorkspaceName;

    IFeatureClassName tFeatClassname = (IFeatureClassName)new FeatureClassName();
    IDatasetName tDatasetName = (IDatasetName)tFeatClassname;
    tDatasetName.Name = shapeName;
    tDatasetName.WorkspaceName = tWorkspaceName;

    IFieldChecker fieldChecker = new FieldChecker();
    IFields sFields = sfeatClass.Fields;
    IFields tFields = null;

    fieldChecker.InputWorkspace = sdataset.Workspace;
    fieldChecker.ValidateWorkspace = targetWorkspace;

    fieldChecker.Validate( sFields, out fieldErrors, out tFields );
    if (fieldErrors != null)
    {
        IFieldError fieldError = null;
        while((fieldError = fieldErrors.Next()) != null)
        {
            Console.WriteLine(fieldError.FieldError + " : " + fieldError.FieldIndex);
        }
        Console.WriteLine( "[ExportDataViewModel.cs] Errors encountered during field validation" );
    }

    string shapefieldName = sfeatClass.ShapeFieldName;
    int shapeFieldIndex = sfeatClass.FindField( shapefieldName );
    IField shapefield = sFields.get_Field( shapeFieldIndex );
    IGeometryDef geomDef = shapefield.GeometryDef;
    IClone geomDefClone = (IClone)geomDef;
    IClone targetGeomDefClone = geomDefClone.Clone();
    IGeometryDef tGeomDef = (IGeometryDef)targetGeomDefClone;

    IFeatureDataConverter2 featDataConverter = (IFeatureDataConverter2)new FeatureDataConverter();
    invalidObjects = featDataConverter.ConvertFeatureClass(
        sdatasetName,
        null,
        sSelectionSet,
        null,
        tFeatClassname,
        tGeomDef,
        tFields,
        "",
        1000, 0 );

    string fullpath = System.IO.Path.Combine( shapePath, shapeName );
    return System.IO.File.Exists( fullpath );
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.