Well since I don’t have ArcDesktop, and can’t do this.
I will do the easy thing and test my Address Locator Style by code, fun fun fun, NOT!
What do I want to achieve?
1. Basic: Create an Address Locator in a GeoDatabase
2. Optional: Delete an Address Locator in a GeoDatabase
3. Advanced: Use an Address Locator in a GeoDatabase
Well I decided to start from the ESRI example, that creates an Address Locator in a Personal GeoDatabase (after refactoring):
The main class:
- public class AddressLocatorUtils
- {
- public void Create(string styleName, string mdbFilePath, string featureClassName, string locatorName)
- {
- var locatorStyle = LocatorWorkspaceUtils.Instance.GetLocatorStyle(styleName);
- var dataset = AccessWorkspaceUtils.Instance.GetDataset(mdbFilePath, featureClassName);
- LocatorWorkspaceUtils.Instance.SetLocatorDatasetName(dataset.FullName, locatorStyle);
- if (LocatorWorkspaceUtils.Instance.IsLocatorValidForSave(locatorStyle))
- {
- LocatorWorkspaceUtils.Instance.AddLocatorStyle(locatorName,mdbFilePath,(ILocator)locatorStyle);
- }
- else
- {
- throw new ApplicationException("Something went wrong...");
- }
- }
- }
The utils:
- public class LocatorWorkspaceUtils
- {
- private readonly ILocatorManager2 _locatorManager;
- #region Singleton
- private static readonly LocatorWorkspaceUtils instance = new LocatorWorkspaceUtils();
- // Explicit static constructor to tell C# compiler
- // not to mark type as beforefieldinit
- static LocatorWorkspaceUtils()
- {
- }
- private LocatorWorkspaceUtils()
- {
- EsriInitilization.Start();
- _locatorManager =
- (ILocatorManager2)Activator.CreateInstance(Type.GetTypeFromProgID("esriLocation.LocatorManager"));
- }
- public static LocatorWorkspaceUtils Instance
- {
- get { return instance; }
- }
- #endregion
- public ILocatorStyle GetLocatorStyle(string styleName)
- {
- return GetLocatorStyle(styleName, "");
- }
- public ILocatorStyle GetLocatorStyle(string styleName, string fileLocation)
- {
- var locatorWorkspace = GetLocatorWorkspace(fileLocation);
- // Get the locator style to base the new locator.
- return locatorWorkspace.GetLocatorStyle(styleName);
- }
- public void SetLocatorDatasetName(IName datasetName, ILocatorStyle locatorStyle)
- {
- var referenceDataTables = (IReferenceDataTables)locatorStyle;
- var enumReferenceDataTable = referenceDataTables.Tables;
- enumReferenceDataTable.Reset();
- var referenceDataTableEdit = (IReferenceDataTableEdit)enumReferenceDataTable.Next();
- referenceDataTableEdit.Name_2 = (ITableName)datasetName;
- }
- public bool IsLocatorValidForSave(ILocatorStyle locatorStyle)
- {
- return ((IReferenceDataTables)locatorStyle).HasEnoughInfo;
- }
- public void AddLocatorStyle(string styleName, string fileLocation, ILocator locatorStyle)
- {
- var locatorWorkspace = GetLocatorWorkspace(fileLocation);
- locatorWorkspace.AddLocator(styleName, locatorStyle, "", null);
- }
- private ILocatorWorkspace GetLocatorWorkspace(string fileLocation)
- {
- return _locatorManager.GetLocatorWorkspaceFromPath(fileLocation);
- }
- }
And AccessWorkspaceUtils contains:
- public IDataset GetDataset(string mdbFilePath, string featureClassName)
- {
- // Open the feature class to use as reference data.
- IWorkspaceFactory2 workspaceFactory2 = new AccessWorkspaceFactoryClass();
- var featureWorkspace = (IFeatureWorkspace)workspaceFactory2.OpenFromFile(mdbFilePath, 0);
- // Set the feature class as the primary reference data table for the locator.
- return (IDataset)featureWorkspace.OpenFeatureClass(featureClassName);
- }
My test:
- [TestMethod]
- public void Create_DllShepherdAddressLocator_AddressLocatorCreated()
- {
- const string styleFileName = "Dll Shepherd Address";
- const string referenceDataStyleName = "ZIP 5-Digit";
- var styleName = String.Format("{0} - {1}", styleFileName,
- referenceDataStyleName);
- _addressLocatorUtils.Create(styleName, @"C:\Projects\Testings\Esri.AddressLocator\Esri.AddressLocator.CoreTests\bin\Debug\Israel_for_Roy.mdb",
- "Streets", "New Dll Shepherd Locator");
- }
And it works, it create a style with the name.
Before:
After:
Well we passed 1.
And then I tested it on something I created and it failed on:
- var referenceDataTables = (IReferenceDataTables)locatorStyle;
With this Exception:
System.InvalidCastException was unhandled by user code
Message=Unable to cast COM object of type 'System.__ComObject' to interface type 'ESRI.ArcGIS.Location.IReferenceDataTables'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{600A5898-DDC1-11D3-9F74-00C04F8ED1C4}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
I decided that though ESRI help might be not very helpful here, their help in ArcCatalog might be better. So I asked Vered to test it and it just asked Vered if she wanted to send the Error to ESRI after closing her ArcCatalog – she almost killed me!
The exception is thrown simply because locatorStyle does not implements the IReferenceDataTables interface. Which is weird because locatorStyle can be converted to ESRIGen2AddressLocatorStyle:
As you can see ESRIGen2AddressLocatorStyle inherits from ESRIReferenceDataAddressLocatorStyle which implements IReferenceDataTables. The weirdness doesn’t stop here looking at the source for ESRIGen2AddressLocatorStyle:
- namespace ESRI.ArcGIS.Location
- {
- [CoClass(typeof (ESRIGen2AddressLocatorStyleClass))]
- [Guid("655C5C62-6478-11D3-9F57-00C04F6BDF06")]
- [ComImport]
- public interface ESRIGen2AddressLocatorStyle : ILocator
- {
- }
- }
It only implements ILocator and I can’t even find ESRIReferenceDataAddressLocatorStyle, I started to think I can’t read this diagrams but:
According to this both ESRIReferenceDataAddressLocatorStyle and ESRIGen2AddressLocatorStyle are classes and one inherits from the other – exactly like I thought!
TODO: add link in “after refactoring” to the post about refactoring ESRI part 1
Resources:
Keywords: ESRI, ArcObjects, Access, unit test, address locator