Tuesday, October 8, 2013

ArcPad 10.2 Fun

I know I haven't posted in a LONG while, but I've encountered a problem with ArcPad 10.2 that I haven't found ANYTHING on while Googling, and since this version is so new, I thought it would be good to get this information out ASAP.

First, let me set up how this problem manifested.  I have an ArcPad 'application' (read: AXF file paired with Applet) that handles new and existing feature creation to display some pre-filled information on an EDITFORM.  This information involves retrieving the actual new/existing feature shape.

Previously (i.e., ArcPad 10.0), I identified the selected feature through the Map.SelectionBookmark property, and applied that bookmark to the Map.SelectionLayer.Records (the SelectionLayer is my layer of interest).  (On a side note...I use the SelectionLayer instead of the EditLayer because if the user has two layers active for editing - e.g., a point and a line layer - ArcPad doesn't seem to be able to tell that the current open form is for one or the other.)  This worked just fine regardless of whether this was a new feature or an existing feature.  A new feature of course does not have a record yet; however, in the interests of minimizing subroutines, I dealt with that case right before retrieving the value I needed from the feature (pulling it from the EDITFORM instead), and the code execution still passed through the record selection.  Everything worked just fine.

Upgrade to 10.2. 

All of the sudden my EDITFORM was cleared of some previously filled fields when I created a new feature.  I had populated the current date and user in a DateTime control and a ComboBox control.  These were wiped as soon as I attempted to set the bookmark of the line layer's recordset.  Mind you, I hadn't DONE anything with that information yet - it was just the act of setting the recordset's bookmark to an invalid number (-1, which is what Map.SelectionBookmark is for a new feature).  My theory is that this somehow disconnected the EDITFORM from the new feature (because the bookmark of the recordset associated with the EDITFORM was set to something invalid), but I don't have the time to test it.  The odd thing is that I can test the value of the controls at any point and it always comes out correctly - it just won't actually display.

SO, the SOLUTION!

To fix this, before setting the recordset bookmark in my function designed for that purpose, I test to see whether Map.SelectionBookmark is -1 (the value for a new feature).  If it is, I do not attempt to retrieve the recordset and simply pass a value of Nothing back for my recordset.  My main code then handles the Nothing value for the recordset by pulling from the EDITFORM's shape field instead.

Sunday, November 11, 2012

Excel VBA and Reference Styles


I encountered something new with Excel reference styles (i.e., A1 vs. R1C1) the other day.  I've mostly used the reference styles when using the Cells.Formula or Cells.FormulaR1C1 properties...for these, you use A1 for the former and R1C1 for the latter, and most importantly, it doesn't matter what reference style you've actually specified in the workbook - Excel just figures it out.

The other day, I tried to use the Range.Validation.Modify function in VBA for the first time.  As is my custom (for ease of programming), I had set the reference style of the workbook to R1C1 before starting.
  
However, not thinking much about it, in the formula of the Modify command, I used A1 style - mostly because Excel had never cared which way I went with the Formula properties, also because I figure this is the style the end user will have.

BIG problem, evil error...I got a nondescript '400' error message.  Debugging showed that the error description was "Application-defined or object-defined error"...big help there.  Hours and hours of Googling were no help.
 
At long last, I thought to check the reference style.  Voila!  When I changed the reference style to R1C1, the code worked!  So, unlike the Formula/FormulaR1C1 property of Cells, apparently Excel will NOT convert your reference style on the fly for the Formula1 property of the Range.Validation.Modify method.
 
So, this wasn't working:
    Dim userValidation As Validation
    Set userValidation = ActiveSheet.Range("C1").Validation
    userValidation.Modify xlValidateList, xlValidAlertStop, _
        xlBetween, "=Lists!$G$2:$G$20"
 
BUT this does:
    Dim userValidation As Validation
    Set userValidation = ActiveSheet.Range("C1").Validation
    userValidation.Modify xlValidateList, xlValidAlertStop, _
        xlBetween, "=Lists!R2C7:R20C7"
 
(when the workbook is set to R1C1 notation)
 
Of course, not knowing what the end user might have, it's necessary to do a check:
Dim userValidation As Validation
Set userValidation = ActiveSheet.Range("C1").Validation
If Application.ReferenceStyle = xlA1 Then
userValidation.Modify xlValidateList, xlValidAlertStop, _
xlBetween, "=Lists!$G$2:$G$20"
Else 'ReferenceStyle = xlR1C1
    userValidation.Modify xlValidateList, xlValidAlertStop, _
xlBetween, "=Lists!R2C7:R20C7"
End If
 
I hope this saves some other poor person from hours of Googling!  It is really such a simple thing, but it didn't occur to me for so long!

Sunday, July 29, 2012

Labeling Supporting Layers in ArcPad

Googling didn't help me much on this topic so I thought it might be worth sharing...regarding labeling background layers for data exported from ArcMap to ArcPad using the ArcPad Data Manager extension ("Get Data for ArcPad" tool) for ArcGIS 10.

The scenario that prompted my discovery was this: I had an ArcMap document that contained the geodatabase feature classes that I needed to check out as well as several supporting layers - parcels, streets, streams, etc.  I wanted the streets to be labeled, but did not need to check them out for editing.  I labeled the streets within the ArcMap file.

Initially I tried exporting the streets as a background shapefile.  However, the labels did not transfer when I opened the exported map file in ArcPad.  After a bit of experimenting I discovered that exporting the streets as a background AXF file kept the labels intact. I suppose in retrospect this does make sense, as the AXF files are supposed to be these wonderful all-encompassing databases.

So there you go, if you want to label your background layers in an export for ArcPad, make sure to export them to an AXF file!

Friday, June 29, 2012

Capturing Button Clicks in ArcObjects

It's been quite a while since I've posted...I've been busily moving myself to North Carolina for a contract position as a GIS Developer with the City of Charlotte.  I'm working through a company called Systemtec.  Everything is going great and Charlotte is a lot of fun!  But with all the commotion involved in moving to a new city, this blog fell to the wayside!

This week, I found something fun in ArcObjects that I thought I should share, as it took a bit of Googling and then some guessing to figure out, so clearly there need to be more posts on the topic!  In particular I found it difficult to find an example of this for VB.net in ArcGIS 10 (rather than 8.3 or VBA) - the syntax is a little different.

My goal in doing this was to determine when the user clicked the Merge button on the Editor menu in ArcMap (for context, I am developing an Editor Extension Add-In for ArcMap 10 using VB.net).  Because Merge works differently from many of the other tools - a bit of experimentation showed that it didn't trigger the OnCurrentTaskChanged event in the Editor - this proved to be a bit problematic.

post by Kirk Kuykendall set me in the right direction - use the ICustomizationFilter interface.  This allows you to listen for ANY button click (and other things - see the ArcGIS help) and react appropriately.  (Note that the button names you'll need are available here.)  It's designed to prevent the user from doing things you don't want him to do (e.g., accessing VBA, clicking buttons, using tools, etc.).  This is done by setting the result of the function to TRUE - this is one of those tidbits that isn't explicitly stated anywhere that I could see, but a true result from the OnCustomizationEvent function prevents the user from doing whatever it was he was trying to do.

In my case, I didn't want to prevent the user from doing anything, I just wanted to KNOW if he did something.  To do this, just return false after executing whatever code you're interested in, and you can detect the button clicks without affecting the usability of the program.  Only trick is that apparently only one customization filter can be active at a time, so if you have a bunch of different add-ins/dlls running that each has its own filter, that could be a problem.

So enough of that, here's the code I wrote to capture the user clicking the button:

First, create a NEW class module and put in code like this:


Public Class clsCustomizationFilter
  Implements ESRI.ArcGIS.Framework.ICustomizationFilter


  Public Function OnCustomizationEvent(custEventType As _
   ESRI.ArcGIS.Framework.esriCustomizationEvent, eventCtx As Object) As Boolean _
   Implements ESRI.ArcGIS.Framework.ICustomizationFilter.OnCustomizationEvent
   
   If custEventType = ESRI.ArcGIS.Framework.esriCustomizationEvent.esriCEInvokeCommand Then
      Dim cmd As ESRI.ArcGIS.Framework.ICommandItem
      cmd = TryCast(eventCtx, ESRI.ArcGIS.Framework.ICommandItem)
      If cmd.Name = "Editor_Merge" Then
 ImperviousEditorExtension.g_blnDeleteOK = True
      End If
   End If


   Return False


  End Function


End Class

The line ImperviousEditorExtension.g_blnDeleteOK = True is where you would put whatever code you want to have run as a result of the button click.  The "Editor_Merge" name can be replaced with the name (from the link above) of any button you want to monitor.  Note the key "Return False" at the end - including this means that you don't stop the user from completing the merge or whatever else he wants to do.  (If for whatever reason you wanted to stop him from doing something, write a condition to check and within that condition Return True.)

To activate this class, take two steps.  First, assuming you're doing this in an editor extension, in the editor extension class create a global variable:
Public Shared m_Filter As ESRI.ArcGIS.Framework.ICustomizationFilter

(if you're not using an editor extension, put this in whatever root module you have)

Second, put this code somewhere that makes sense:

m_Filter = New clsCustomizationFilter
My.ArcMap.Application.LockCustomization("password", m_Filter)
For example, I included it in my OnStartEditing event handler.

Now, to keep things neat and tidy, I unlocked the customization once I was done, so I included the following line in my OnStopEditing event handler:
My.ArcMap.Application.UnlockCustomization("password")

There you go!  A method to detect the user's button click on any button in the interface.  Hope it helps you as much as it did me!!

Friday, December 16, 2011

Working out kinks in VB.net/BASINS

I mentioned last week that I was working on revising a portion of the BASINS source code to reproduce the statistics and advice previously calculated by the antiquated HSPEXP program. I'm happy to report that I've gotten the portion of the code I was working with up and running, producing area summaries, statistics, and graphs using Virginia Tech's standard formatting, in a new(ish) program that just runs the statistics and does not require BASINS to be launched. Getting the portion of the code up and running took a little time but was not complicated, after addressing the issues in my last post. However, creating a setup file that would run on Windows 7 proved to be a little more challenging, and I thought I'd write about it to help both future BASINS coders and general VB.net coders alike.

My first problem was that the code I'm working with requires an old DLL created (I think) using FORTRAN - hass_ent.dll. I had tried to enter the version of the DLL published with EPA's version of BASINS 4 into the registry on a Windows 7 machine - no luck. Additionally, the version of BASINS available from EPA would not install on a Windows 7 machine. I believe I mentioned in my last post that Aqua Terra has released an updated version of BASINS on their website, which is nearly impossible to find if you don't know what you're looking for. So I tried downloading and installing the "Installer for GenSCN and WDMUtil" available at that website (following the 'keep it simple stupid' mentality, I decided to try installing just what I needed - WDMUtil and HSPF - rather than the full-blown package). Ta-da! It installed. The version of HSPF in that package does not run, but WDMUtil does. The full blown BASINS upgrade includes a newer version of HSPF (3.0), my hunch is that it will run on Windows 7...but again, keeping it simple, I haven't messed with that yet. All I needed for my purposes was to get something to install hass_ent.dll, and the GenSCN and WDMUtil installer was successful for that purpose.

My next problem arose from the fact that I had updated the references for the BASINS source code in a rather patchwork fashion...first I tried downloading DLLs from MapWindow, then I realized several of the needed files were actually available with the BASINS installation available from EPA and just copied the ones I needed, and then when I was still having trouble I upgraded my BASINS installation as above and referenced those DLLs...so depending on when I brought which projects into my VB.net solution, projects using the 'same' DLL might actually reference two different files. Additionally, there was a BASINS project available that compiled into MapWinUtility.dll that was slightly different from the MapWinUtility.dll that seems to be the default for MapWindow, and of course my patchwork solution was referencing both of them. Once I finally got the code to compile after all the various downloads and updates I didn't think to check that all 15 of the member projects were referencing the same DLLs.

I was receiving multiple errors as a result of this. Additionally, once I attempted to publish the file, I got an actual error in Visual Basic 2010 Express that would no longer let me compile the project. These errors were "two or more files have the same target path" within the development environment and "reference in the manifest does not match the identity of the downloaded assembly" while attempting to install the code on a new computer. I had an earlier error "must be strong signed in order to be marked as a prerequisite" that had caused me to change the status of stdole.dll from 'prerequisite' to 'include' in the Publish->Application files screen for my main project (note that the file it said needed to be strong signed was NOT stdole.dll...but fixing that one fixed the error). I think that change might have launched the other errors... At any rate, after googling and googling I finally started checking the references and discovered I had several with the same name pointing to different actual files. I changed the same-named references in all the projects to point to the same DLLs and poof! my errors vanished.

I suppose this is no great surprise - kind of a 'well, duh' kind of moment. I agree. However, I think it is an easy mistake to make with code acquired WITHOUT all the required references, code that forces you to go identify and download all those references yourself. I had googled and tried things for hours before thinking to check my individual project references, so I'm suggesting it here in hopes it may save someone else a lot of wasted time!

Friday, December 9, 2011

Working with Open Source BASINS

This week I've started tackling a fun new project - working with portions of the open source BASINS software. It has been challenging and educational. I've learned a bit about MapWindow and I've also seen that the code needed to access WDM files is really not so bad.

I started on this project because my colleagues at Virginia Tech need a new way to calculate hydrology calibration statistics. We've been using HSPEXP for years, and it does just what we want, but it just doesn't work on modern computers. You can coax it along using XPMode in Windows 7, but even then it has a tendency to randomly freeze up. It's just not happy anymore, and it's time we laid it to rest.

So, fortunately for us, a former graduate student who used to work with me when I worked at Virginia Tech now works for Aqua Terra, the company that maintains BASINS and HSPF. He told us that they've been working on a way to calculate the same statistics that HSPEXP calculates - without the old DOS program and interface.

Fortunately BASINS is open source, so I could get my hands on the code early and customize it for our use. However, things started to get complicated quickly. The folks at Aqua Terra directed me to the subversion download site for BASINS, from which I obtained the code. Fortunately it's written in VB.net, with which I'm quite familiar! However, I quickly learned I needed far more than just the BASINS code.

I discovered that I needed to download several MapWindow projects as well - specifically D4EM, MapWinUtility, and SwatObject. I read a bit more about MapWindow while searching through their site and I must say I find it very exciting - an open source GIS platform for which you can write code in VB.net. I am really interested in developing some GIS programs with the MapWindow libraries, and hope to get in to that once this current project is done.

I also updated my BASINS 4 installation - I'm still not entirely sure if this was necessary, but it I think perhaps it provided the most current version of some DLLs. Some method of BASINS installation is needed to provide hspfmsg.mdb and hspfmsg.wdm. Interesting to note that the update I linked is for 9/2011...which is newer than the current version available on the EPA website, dated 5/2010. Most of the DLLs provided by the BASINS installation can be obtained from MapWindow, but I think the hspfmsg files and a couple DLLs like TableEditor are only available with BASINS. As of the 5/2010 revision, BASINS would not install in Windows 7 except under XPMode. I'm hoping that perhaps if I copy the hspfmsg files to a new computer and get the DLLs from MapWindow I won't have to install BASINS on a Windows 7 computer...this remains to be tested. It is also possible that the 9/2011 version of BASINS will install under Windows 7...this also remains to be tested.

So for now I'm working with the BASINS code on Windows Vista. I ended up just extracting the tool I needed, as in the end we're hoping to have a standalone executable that just calculates the statistics - and maybe runs HSPF - rather than having to launch the full-blown BASINS system. So far I've gotten the statistics calculated, but I still need to work on some connections for the graphs and summary reports, as they're not printing out correctly with the code I've extracted so far. Once everything seems to be working on Vista (where BASINS does install), I'll try transferring everything to a Windows 7 machine and tackle the problems that are sure to arise. I'll let you know how that goes!


Friday, December 2, 2011

Happy Thanksgiving!

Ok, so I know it's a little late, but Happy Thanksgiving! I spent the week in Pittsford, NY visiting my sister at her new house there. Pittsford is a very nice-looking village that borders on the Erie Canal.

Speaking of canals, I just submitted an abstract for the 2012 ASABE international meeting in Dallas, TX. I'm hoping to present the results of my PhD research on modeling for inland navigational canals. I should have done this last year, but my work on the BP Oil Spill kept me too busy to think about anything else during the submission window. As I work on the paper for the conference, I'll also be working on a final journal article for my research.

With the past holiday week, I haven't done much blog-worthy technical work, so I guess that's all for now!