Posted by: Jeff Germain | March 25, 2009

Developing with ArcObjects on Windows 64-bit OS

Just a week into running on my new development box, Windows Server 2008 64, and everything had been smooth… until this bump in the road. While writing a utility COM component to extend ArcGIS Server, I ran into a serious gotcha. The issue actually was exposed while I was writing/running unit tests. Spinning up any ArcObjects in my tests were failing with the following runtime error:

System.Runtime.InteropServices.COMException: Retrieving the COM class factory for component with CLSID {E01BE902-CC85-4B13-A828-02E789E0DDA9} failed due to the following error: 80040154.

ArcObjects for .NET uses managed COM interop assemblies to access the 32-bit COM objects (unmanaged C++ core ArcObjects libraries). So, turns out the test project’s “Platform Target” property was set to “Any CPU”.

The Fix?

Change the project’s “Platform Target” property from “Any CPU” (VS defaults to this) to “x86”.

I’ve got a DynamicMapServiceLayer with 1000’s of features. So it takes a while to draw the overlay. This extra draw time justifies displaying a “loading” indicator image in the UI so as not to give the impression that the application has hung. So I searched for an event I could hook into to to get notification when all layers have finished drawing on the map. I tried the events on GMap2 (dragstart, dragend, movestart, moveend, zoomstart, zoomend), and while these let me know when to display my loading icon, they didn’t tell me when all layers had finished drawing. No luck. After pulling my hair out I got feedback from Praveenkumar Ponnusamy at ESRI.

ArcGIS JS Extension for Google Maps API v1.2

v1.2 will include a new event for the DynamicMapServiceLayer that you can wire up to get notification when the layer has finished drawing.

v1.2 is expected to be released around the end of October.

Update: v1.2 has been released and delivers with it Dojo v1.2. You may now listen and respond to the update event that has been added to DynamicMapServiceLayer, ImageServiceLayer, and TiledMapServiceLayer.

ArcGIS JS Extension for Google Maps API v1.1

In the meantime, here is a hack for v1.1. Note, this is NOT officially supported by ESRI and WILL NOT work at v1.2.

Download page sample

Code

<script type="text/javascript">
var gmap, dynamicMapServicelayer;

function initialize() {
  //Load Google Maps
  gmap = new GMap2(document.getElementById("map_canvas"));
  gmap.addControl(new GLargeMapControl());
  gmap.enableScrollWheelZoom();
  gmap.setCenter(
    new GLatLng(36.62513340485903, -112.32421875), 3);

  addUpdateEventWorkaround();

  //create dynamic map service layer
  dynamicMapServicelayer =
    new esri.arcgis.gmaps.DynamicMapServiceLayer(
    "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/" +
    "Specialty/ESRI_StatesCitiesRivers_USA/MapServer",
    null, 0.75, dynamicMapServiceLoaded);
}

function dynamicMapServiceLoaded(mapService) {
  gmap.addOverlay(dynamicMapServicelayer);
}

function addUpdateEventWorkaround() {
  /************************************************/
  // !!!!!!!! ALERT: IMPORTANT NOTE !!!!!!!!
  // This workaround is NOT officially supported and WILL NOT work
  // at version 1.2 So, PLEASE include a FIXME note in your code to
  // remove this workaround once you start using version 1.2
  /************************************************/
  // save the original redraw handler
  var _redrawHandler =
    esri.arcgis.gmaps.DynamicMapServiceLayer.prototype._redrawHandler;
  // create a new method to handle layer redraw
  esri.arcgis.gmaps.DynamicMapServiceLayer.prototype._redrawHandler =
    function() {
        // setup listener for image load event
        var listener = GEvent.addDomListener(this._img_loading, "load",
            function() {
              GEvent.removeListener(listener);
              listener = null;
              GLog.write("Map image has been loaded");
              // include code here to remove your "image loading" message
            });
        // call the actual redraw handler
        _redrawHandler.apply(this, arguments);
  }
}

</script>

Thanks Praveenkumar!

Posted by: Jeff Germain | September 12, 2008

Microsoft Save as PDF or XPS

Yesterday I was creating user and install guides for some software we’re wrapping up. Typically I use the open source PDFCreator print driver from Word, but it doesn’t create bookmarks from headings in the Word documents and the images lose quality. Not to worry… 2007 Microsoft Office Add-in: Microsoft Save as PDF or XPS does this and more and all from within Windows programs for FREE.

More on XPS format

Posted by: Jeff Germain | August 20, 2008

Cache Dependency in ASP.NET

Cool things with System.Web.Caching.CacheDependency. This simple example stores some settings for a table of contents control in an ASP.NET application. The settings in the configuration file apply to all users. One requirement is that the admin must be able to edit these settings and make them available to the application without interruption. This we achieve with the CacheDependency class.

/// <summary>

/// Key for the TableOfContentsSettings stored in

/// ASP.NET application’s Cache.

/// </summary>

private const string _tocSettingsIdentifier =

    “TableOfContentsSettingsIdentifier”;

 

/// <summary>

/// Gets or sets the table of contents settings.

/// </summary>

/// <value>The table of contents settings.</value>

private NameValueCollection TableOfContentsSettings

{

    get

    {

        object settingsCollectionObject =

            this.Page.Cache[_tocSettingsIdentifier];

        if (settingsCollectionObject != null)

        {

            return settingsCollectionObject

                as NameValueCollection;

        }

        else

        {

            // Read the TOC settings stored in our XML file

            NameValueCollection settingsCollection =

                ReadConfiguration();

 

            // Support “real time” updates where admin edits

            // config file. We’ll set up a dependency on the

            // the XML config file. If the file is modified in any

            // way, it will be purged from the cache, forcing

            // this block to run the next time the

            // TableOfContentsSettings is requested. Cool.

            string filename = this.GetConfigurationFilePath();

            CacheDependency dependency =

                new CacheDependency(filename, DateTime.Now);

            this.Page.Cache.Insert(_tocSettingsIdentifier,

                settingsCollection, dependency);

 

            // Set the changed flag so we know to update

            // the browser. Don’t set it if first time loading.

            if (this.Page.IsPostBack || this.Page.IsCallback)

            {

                this.HasSettingsChanged = true;

            }

        }

 

        return config;

    }

    set

    {

        this.Page.Cache[_tocSettingsIdentifier] = value;

    }

}

Read up on the options the CacheDependency class gives you. You can set up dependencies on other objects, files, arrays, etc.

See Also

Caching Application Data

Something I wanted to streamline for my development team was icon and bitmap management; or rather taking as much of the decision making process out of the equation. The strategies I have taken have the following benefits.

Time / Efficiency
  • I don’t want developers spending any time digging around for or capturing an icon/bitmap. Period.
  • I don’t want 10 different methods written to assign an image to a control; which would require a minimum of 10 unit tests be written, and so on.
  • I do want to be able to change an icon or bitmap in one place and have that automatically update all projects. Really, how many copies of the folder browser image do you need across projects?
  • I want a single location where our custom ArcGIS command icons are stored.
Consistent Presentation Layer
  • Icons and bitmaps should be consistent across the presentation layers. I prefer to use Windows icons to ensure user recognition of functionality and purpose. I don’t want icons from different Windows OS mixed either. Office XP icons look dated on Vista… And Office 2000 icons look like ass on XP and Vista. By the same token, if your company has spent the money and bought an icon library then you want only images from that library used in your software. The one acception to this rule is the outdated ArcGIS icon library. I will mix these into my UI for example when a button’s functionality is to select features.

What follows is a brief primer on how to get started building an icon and bitmap library, and a utility class with methods for retrieving those images.

The Utilities Assembly

I have created a sample Utilities library to be referenced by any project requiring icons or bitmaps. This includes custom Windows Forms, ArcGIS ICommand classes, custom property pages, etc. This project contains a “Resources” folder that holds the icons and bitmaps, has entries in the Resources.resx file, and an IconHelper class.

Adding Icons and Bitmaps

I started by first creating a “Resources” folder within the project. Next, I built my icon and bitmap library by adding the desired icons and bitmaps to that folder. I rename these files appending “Icon” or “Bitmap” (Example: Save.ico to SaveIcon.ico). This makes it easier to identify the image type when using the My feature in VB.NET (Example: My.Resources.SaveIcon).

The IconHelper Class

I created enums for both icons and bitmaps providing intuitive names… the actual file name minus the “Icon” or “Bitmap” you may have appended to it. Here you could do some logical groupings if you wanted for such things as EnumTextEditorIcons and such.

This is just one example that is included in the sample.

The enum:

”’ <summary>

”’ Enum for common Icons.

”’ </summary>

Public Enum EnumIcon

AddNew

Copy

Delete

ErrorProvider

Folder

Help

etc…

End Enum

The method to retrieve the icon using the enum:

”’ <summary>

”’ Gets an icon from the embedded resources.

”’ </summary>

”’ <param name=”iconImage”>The icon image.</param>

Shared Function GetIcon(ByVal iconImage As EnumIcon) As Icon

Select Case iconImage

Case EnumIcon.AddNew

Return My.Resources.AddNewIcon

Case EnumIcon.Copy

Return My.Resources.CopyIcon

Case EnumIcon.Delete

Return My.Resources.DeleteIcon

Case EnumIcon.Folder

Return My.Resources.FolderIcon

Case EnumIcon.Help

Return My.Resources.HelpIcon

etc…

Case Else

Return Nothing

End Select

End Function

Putting it all together in the UI:

‘ Assign an image to a Button control

Me.FolderBrowserButton.Image = _

IconHelper.GetIcon(EnumIcon.Folder).ToBitmap()

 

‘Add bitmap MxCommand

MyBase.m_bitmap = _

IconHelper.GetIcon(EnumCustomArcGisCommands.ReportsGenerator).ToBitmap()

The Sample

The sample illustrates how to use the utility class in a Windows Form and shows other ways to expand this idea.

Download VB.NET sample or C# sample.

Posted by: Jeff Germain | February 14, 2007

Source Code Documentation in VB.NET

I recently discovered GhostDoc which is a free add-in for Visual Studio .NET (2003 & 2005). It’s a handy tool that generates XML documentation comments. This tool was written for C# developers but has extended beta support for VB.NET. What’s nice about it is that it reinforces the idea of using full descriptive names when creating methods, properties, parameters, etc. It will create a descriptive summary by dissecting the member name and formulating a sentence. It’s about as hands free as it gets!

I’ve been using it in my VB.NET projects with much success. While it doesn’t always get it 100% right, it does get you 95% of the way there. Definitely a time saver.

If you want to use it within VB.NET you’ll need to enable this feature in the configuration dialog. Go to Tools | GhostDoc | Configure GhostDoc and select the Options tab. There you’ll find a checkbox for this feature.

I’ve barely scratched the surface of this tools capabilities. You can set it up to add the username or timestamp when documenting members. Lot’s more too! So have a look.

Posted by: Jeff Germain | February 14, 2007

Debugging Custom ArcGIS 9.1 Components in Visual Studio .NET 2003

If you have both the .NET 1.1 and 2.0 Frameworks installed on your development machine you will run into troubles when trying to debug ArcGIS 9.1 components written on the .NET 1.1 Framework. This is because ArcMap is an unmanaged application and as such when it initializes it loads the most current .NET Framework installed on the system. Not to fret though as it’s easily overcome using a configuration file.

Simply copy the following to a text file and save it as <ApplicationName>.<ApplicationExtension>.config
So, a config file for ArcMap would be named ArcMap.exe.config.

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
<startup>
<supportedRuntime version=”v1.1.4322″ />
</startup>
</configuration>

Save this file to the ArcGIS bin directory. The default location for this directory is C:\Program Files\ArcGIS\Bin.

Now you’re set to debug .NET 1.1 components. When you need to debug .NET 2.0 components simply rename the file to ArcMap.exe.config.xxx.

You can read more from ESRI here.

Posted by: Jeff Germain | February 2, 2007

Task Manager Missing Tabs

I’ve had an annoying problem for a while now and finally got around to looking into it. My Task Manager was missing all it’s tabs. In fact, it was getting displayed without being hosted within its usual Windows Form. I had no idea what I did to deserve this. See below.

Task Manager Issue

Anyways, it’s an easy fix. Simply double-click anywhere around the border to viola! it’s back!. Double-click again and it goes back into this minimalist mode.

Task Manager Fix

Task Manager Fixed

« Newer Posts

Categories