Using categories for discrete shapes

I’m trying to get a couple of shapes in a (polygon) shape file to fill with a specific color.
VB.Net code looks like:

    Dim fieldIndex As Integer = LTag.Shpfile.Table.FieldIndexByName("GRIDCODE")
    For idx As Integer = 0 To LTag.Shpfile.NumShapes - 1
        Dim fldval = LTag.Shpfile.CellValue(fieldIndex, idx)
        Dim tp As Type = fldval.GetType
        If tp = GetType(Double) Then
            Dim thisfieldval As Integer = CInt(DirectCast(fldval, Double))
            ' check if this is one of the targetted shapes
            If ScIDs.Contains(thisfieldval) Then
                Dim newcat As ShapefileCategory = LTag.Shpfile.Categories.Add(thisfieldval.ToString)
                newcat.Expression = "[GRIDCODE]"
                newcat.ValueType = tkCategoryValue.cvExpression
                Dim newoptions As ShapeDrawingOptions = newcat.DrawingOptions
                newoptions.FillColor = Convert.ToUInt32(RGB(0, 0, thisfieldval))
                newoptions.FillColor = Convert.ToUInt32(RGB(0, 0, 255))
                newoptions.LineWidth = 2
                newoptions.LineColor = utils.ColorByName(tkMapColor.Blue)
            End If
        End If

I also tried without the Expression statement and a ValueType = tkCategoryValue.cvSingleValue but neither are working.
By the time you get to the last line of code, there are a correct number of Categories in the shapefile, but the map does not change. I guess the ApplyExpression call may not be right as there really is no expression to be evaluated.

Reading the documentation:
It’s the responsibility of the developer to map the new category to the particular shape by either:

  • specifying [ShapefileCategory.Expression]
  • by using [Shapefile.set_ShapeCategory()]

The Shapefile.set_ShapeCategory function looks more appropriate, but my (version AxMap object tells me that it is not a member of Shapefile.

In short: any help would be very much appreciated.

Hello @pan054

Forgive me if I’m mistaken, I haven’t actually tried running it, but looking it over, comparing with similar code, I think what might be missing is that you want to render where GRIDCODE = the specific field value? Perhaps try this:

newcat.Expression = "[GRIDCODE] = " & thisfieldval 


Hi Jerry,
Thanks lots for helping. Your comment about the expression solved the problem. I would have bet a fair bit of money that I tried that but it didn’t work, probably because there were other things wrong with the category/ShapeDrawingOptions. Be it as it may, it is now working, so you solved that problem, thank you so very much!!

About the Shapefile.set_ShapeCategory(): according to the documentation the function is set_ShapeCategory(int ShapeIndex, int pVal). Taking the set_ away as per the VB.Net convention, it seems to revert to the get_ShapeCategory(int ShapeIndex) and does not accept two variables:

I have no idea how to force the set_ version. I use the ‘drop get_ and set_’ in VB a fair bit, and it usually works, but this one escapes me.

About the Categories
I believe Categories to be a very positive extension for many cases where the shape selection has some regularity that can be caught using an expression. I’m was not ecstatic it had to be implemented excluding the previous capabilities of changing the visual representation of single shapes in a layer. We may end up with hundreds (or more) of categories which describe the same ShapeDrawingOptions, with a possible response penalty.

Anyway, this problem has been solved for now, so many thanks again for your help, Jerry.


I should have been more clear, but I didn’t think about it until I saw your comment.

So in c#, it treats the Set property as a method, and the Get property more like an actual property

set_ShapeCategory(shapeIndex, pVal);
pVal = get_ShapeCategory(shapeIndex);

while in VB, it treats them both more like actual Properties

ShapeCategory(shapeIndex) = pVal
pVal = ShapeCategory(shapeIndex)

I’ll comment on the Categories separately so that you can try the above change.


Regarding the Categories, I wouldn’t mind getting more detail in terms of what you need to accomplish, in case I may be able to provide recommendations.

As an aside:
Are you able or willing to build and maintain your own version of the OCX?

I’ve had a couple customers for whom I’ve maintained their own custom version of the OCX (for their proprietary behavior), and to which I have to occasionally integrate the latest updates from GitHub. It’s extra work, but it allows you to do things outside of the current development path.

As such, you could potentially ‘bring back to life’ some of the deprecated methods. Some of them are still stubbed out in the OCX. You would have to be careful not to step on current Category behavior, but it may be possible to put back the single-shape rendering (although I cannot say for sure without looking a little deeper).

Just food for thought.

Hi Jerry,
Excellent, new trick in my toolbox how to deal with the C# set_ in VB.Net, great, that will be very helpful in the future, thanks for that one!

The application I’m working on at the moment (be it out of interest, not professionally anymore), implements a multi-objective tradeoff evaluation approach that (hopefully) helps river catchment managers looking at tradeoffs when choosing how and where to spend their/our $$ that give them most returns wrt to multiple management objectives (e.g. reducing sediment, improving eco-status). The prototype works on relatively small catchments with a limited number of sub-catchments. After hundreds of thousands or millions of management actions have been tested and filtered, the results (sub-catchment with the most potential to sped $$) are shown on maps.

Wrt maintaining or purpose-adapting the MWG OCX: the maps are a small (but crucial) part of the application. After getting over the Category and Legend hurdles, I expect the standard OCX will be sufficient for purpose. Also, maintaining the OCX means a lot of time investment from somebody.

Cheers, and again thanks heaps for your very kind help,

Between a rock and a hard place.
It is all working nicely now in a test application. When trying to use it in the target app, it turns out that VS can only deal with 32 bit OCX objects, but I had forgotten that my ADO database drivers only work in a 64 bit environment. This little problem may spell the death of the (mapwingis) ActiveX/OCX approach eventually, unless MS comes up with a 64bit VS version.

Hello Francis.

I’m trying to find some documentation on the process, but you should be ok.

Yes, you have to have the 32-bit OCX registered on the development machine in order to work in Visual Studio, but you can still build a 64-bit application, and run it (on a separate machine) with the 64-bit version of the OCX.

I have to debug the whole application with its 32 OCX and 64 ADO drivers. I’m now looking at maybe installing a 32 bit ACE diver for DB access. I’ll keep you informed, even though Paul may object us using this forum as a communication tool :smile:

If you feel adventurous, you could try bouncing between the 32 and 64 bit OCX’s. Register the 32-bit to build the exe. Then unregister the 32 and register the 64 bit. Then run the exe and ‘attach’ the debugger from Visual Studio. You may need to uncheck the “Enable the Visual Studio hosting process” in the Debug settings (although that may not apply when attaching to a process).

Whatever you may learn could benefit others in a similar situation, so it’s valid for this forum :wink:

Addendum: It may be that you only need the 32-bit OCX for Visual Studio in order to open and use the visual designer, but that you could still build and debug the exe with the 64-bit OCX registered??? I may be wrong.

I’m looking at using a 32 bit ODBC driver ( that can live with a 64 bits installed Office system. Some/many 32 bit DB drivers cannot cohabitate with 64 bit Office, but these can, it seems. I’m testing how much work it would be to convert 20years of ADOR/ADOX (simple and fast) development into my pet-hate ODBC/ADO.Net DataAdapter/dataset/datareader approach. Wish me luck.

It turned out to be a storm in a thimble. Installing the 32 bit driver AccessDatabaseEngine.exe /passive ( ‘passive’ being the secret word) and updating the ADO drivers (ADODB V6.1, ADOR 6.0 and ADOX 6.0) allows me to use ADO DB utils a 32 bit environment, with the MapWinGIS OCX. I have been spared from the disconnected DB DataAdapter/Dataset/Datareader rigmarole. Onwards and upwards!

1 Like