IFeatureLayer.FeatureClass returning null

1061
16
08-18-2011 12:04 PM
Highlighted
New Contributor
Hi everyone

This might be a simple doubt. When opening a single .mxd, I can read correctly some properties of the layer, like Name and DataSourceType. When I try to access the FeatureClass, it always returns null. Checking the source inside ArcMap, the FeatureClass is there just as I want. So, why can't I read it programatically?

Here's the relevant part of the code:

namespace WindowsApplication1
{
  public partial class Form1 : Form
  {
    private IMapDocument pMapDocument = null;
    private IMap pMap = null;
    private IEnumLayer pEnumLayer = null;
    private IFeatureLayer pFeatureLayer = null;
    private IDataLayer2 pDataLayer = null;
    private IDatasetName pDatasetName = null;
    private IWorkspace pWorkspace = null;
    private IWorkspaceName pWorkspaceName = null;
    private IUID pUID = null;
    private string p = "password";

    public Form1()
    {
      InitializeComponent();
    }

    private void Form1_Shown(object sender, EventArgs e)
    {
      Application.DoEvents();
      Start("", true);
    }

    private void Start(string sPath, bool inicializando)
    {
      bool saveInsideLayer = true;
      int i;
      string mxd;

      IPropertySet pConnectionProperties = new PropertySetClass();

      if (sPath == "")
      {
        saveInsideLayer = false;
        sPath = @"C:\layer.mxd";
      }

      try
      {
        pMapDocument = new MapDocumentClass();
        if (pMapDocument.get_IsPresent(sPath))
        {
          pMapDocument.Open(sPath, "");
        }
        
        for (i = 0; i < pMapDocument.MapCount; i++)
        {
          pMap = pMapDocument.get_Map(i);

          pUID = new UIDClass();
          pUID.Value = "{E156D7E5-22AF-11D3-9F99-00C04F6BC78E}"; 
          pEnumLayer = pMap.get_Layers((UID)pUID, true);

          pEnumLayer.Reset();
          pFeatureLayer = (IFeatureLayer)pEnumLayer.Next();

          while (pFeatureLayer != null)
          {
            if (pFeatureLayer.DataSourceType.Contains("SDE"))
            {
              pDataLayer = (IDataLayer2)pFeatureLayer;
              if (pDataLayer.DataSourceName is IDatasetName)
              {
                pDatasetName = (IDatasetName)pDataLayer.DataSourceName;
                pWorkspaceName = pDatasetName.WorkspaceName;
                if (pFeatureLayer.FeatureClass != null) // why never true?
                {
                  pConnectionProperties = pFeatureLayer.FeatureClass.ExtensionProperties; 
                }

                pWorkspaceName.ConnectionProperties = pConnectionProperties;
              }
            }
            pFeatureLayer = (IFeatureLayer)pEnumLayer.Next();
          }

          txtServidor.Text = pConnectionProperties.GetProperty("SERVER").ToString();
          txtPorta.Text = pConnectionProperties.GetProperty("INSTANCE").ToString();
          txtDatabase.Text = pConnectionProperties.GetProperty("DATABASE").ToString();
          txtUsuario.Text = pConnectionProperties.GetProperty("USERNAME").ToString();
          txtSenha.Text = pConnectionProperties.GetProperty("PASSWORD").ToString();

          if (saveInsideLayer)
          {
            pMapDocument.ReplaceContents((IMxdContents)pMap);
            pMapDocument.Save();
            pMapDocument.Close();
          }
        }
      }
      catch (Exception ex)
      {
        throw new Exception("Unable to run the code", ex);
      }
    }

  }
}


I'm working in Visual Studio 2005, and using an ArcInfo license for 9.3 version.

Thanks for the attention

Rodrigo Salvador
Reply
0 Kudos
16 Replies
Highlighted
New Contributor III
Hello Rodrigo:

I tested your code with 9.3.1 sp2 and I can get FeatureClass object successfully. I wonder have you tested on other data?

Regards,
Chel
Reply
0 Kudos
Highlighted
New Contributor III
What kind of data source is in this layer that returns FeatureClass null?
Reply
0 Kudos
Highlighted
New Contributor
Dubravko e Chelsea, thank you both for the answers.

Chelsea, in this project I have 3 .mxd files, and I run the code trying to open all of them. In all cases, the FeatureClass returned null for all layers.

Dubravko, I found the DataSourceType as "SDE Feature Class" inside the Source tab (Properties window) insde ArcMap. The line on the code, if (pFeatureLayer.DataSourceType == "SDE Feature Class"), works fine.

I wonder if the problem is in the first layer, which is a GroupLayer in all 3 .mxd. So I try to run not testing this top layer, but all others fails too. In examples I found in documentation, there is no treatment to this, the FeatureClass is callled just as I do in the code. Does it might be a configuration in Visual Studio? Just a guess...

Thanks again. Your help is still needed.
Reply
0 Kudos
Highlighted
New Contributor III
Try this example and we will go one step at time, this has to be simple problem.

http://resources.esri.com/help/9.3/ArcGISDesktop/ArcObjects/esricarto/IMap_Layers.htm

use UID for FeatureLayer.

And if you are trying to use IGroupLayer to find IFeatureLayer.FeatureClass you'll get exception before accesing FeatureClass because IFeatureLayer does not imeplement IGroupLayer
Reply
0 Kudos
Highlighted
Regular Contributor II
If you open the mxd in ArcMap, are the layers broken (red exclamation mark?)  If not, are you running your code as different user than the one opening the mxds?  Can you call open on the IDatalayer.datasourcename object?
Reply
0 Kudos
Highlighted
New Contributor
Drubravko, thanks for the link. I'd change the GUID from IGeoFeatureLayer to IFeatureLayer, but it didn't make much difference. I asked the following test for all layers, whether GroupLayer or not, and all of them failed:


if (pFeatureLayer.FeatureClass != null)
                {
                  MessageBox.Show(pFeatureLayer.Name + " ok");
                }
                else MessageBox.Show(pFeatureLayer.Name + " fail");


Alexander, you gave a great hint. My first goal here is to get the connection properties of the layer and write them down on a window (in which the user must change the properties as he/she wants). So, I do can open IDatalayer.DataSourceName (the property .NameString returns empty (""), but when I set it to an IDatasetName the .Name field is exactly the FeatureClass I want). Thus, the following code works:


pDataLayer = (IDataLayer2)pFeatureLayer;
              if (pDataLayer.DataSourceName is IDatasetName)
              {
                pDatasetName = (IDatasetName)pDataLayer.DataSourceName;
                pWorkspaceName = pDatasetName.WorkspaceName;
                pConnectionProperties = pWorkspaceName.ConnectionProperties;
              }


So, with your help, I'm able to do what I want right now (hope I can change the properties successfully later). Therefore, the IFeatureLayer.FeatureClass still returning null, and I think it's interesting if we keep trying to find a solution for this.

Once again, thank you so much.
Reply
0 Kudos
Highlighted
Regular Contributor II
If the link is broken, then the featureclass will always be null.  If the purpose of the application is to display the layer connection properties and perhaps fix them, then you are on the right track.  You can use the Idatalayer2.Connect method to fix the layers.  Basically read the IName from the layer, display it, change it, make a new IName from the new properties and use the IName to reconnect using Idatalayer2.connect. 
The trick is the IName contains the info you see in the layer source tab of the properties.  It is all the information you need to connect to data without actually making the connection (Open method does that.)   That is available even when the layer is broken.  The FeatureClass property however is a direct link to the data in the database, it is not metadata, it is the actual data, so if the connection is broken, it is null.
Reply
0 Kudos
Highlighted
New Contributor
Sorry, Alexander, I forgot this information to you: the links are not broken (the red exclamation is not there), and that's why I can't figure out why the information is not loaded in IFeatureLayer. On the other side, you said another important thing: the FeatureClass property is a direct link. Maybe that's why this error is happening, I'm not making an explicit connection to the database inside the code. As I told, the information is avaiable in the map properties window, and it makes me think the .mxd connects to the database itself someway, and I need to do it programatically too to be able to get that information. Does it make sense?

About the connections, my first shot to edit the properties follows:


            pMapDocument.ReplaceContents((IMxdContents)pMap);
            pMapDocument.Save(true, false); //are these arguments ok?
            pMapDocument.Close();


I found it in some research, and I'm guessing it will be sufficient. If I can't see it working, I'll try your suggestion. In both cases, I'll post again in order to finish the topic.

Rodrigo Salvador
Reply
0 Kudos
Highlighted
New Contributor
Ok, tests are done.

The code I've paste here failed while saving. So I changed it to Alexander's. And I'm getting a COM Exception on connecting or disconneting.

Does anyone know why? I remember there's something to do with Project Properties -> Build -> check Register for COM interop, but this CheckBox is disabled here.

Thanks

Rodrigo Salvador
Reply
0 Kudos