I am trying to override the drawing of a feature within a custom plugin data source. I believe this entails making a custom IFeatureRenderer.

However, the "renderer" I'd like to design would be 99% the same as a ClassBreaksRenderer, but with a custom Draw override.

What would be the simplest manner to be able to reuse the existing functionality of the ClassBreaksRenderer (including and especially the UI property pages) while still being able to provide a custom Draw implementation?


Since for feature renderers, it is the property page that is registered so that it appears in the UI (renderers themselves are not registered), your best bet is to implement your own property page and relay all (or most) of its calls to an GraduatedColorPropertyPage instance. This class is the property page for class breaks renderers.

Now, for the feature renderer, you have two options.

  1. You implement your own from scratch. You will need to implement most of the interfaces the ClassBreaksRenderer class does as the property page surely relies on them to be implemented.

  2. Again, similarly to the property page, you use composition. Create an instance of ClassBreaksRenderer and route all calls (on all of its interfaces) except possibly the Draw method to that inner instance.

It is clear that option 2 is way more convenient.

EDIT: For both classes, you need to pay attention to methods which return GUIDs or create object instances. Those methods are not routed to an inner instance since you need to return a different, correct GUIDs or instances for your classes. This is the case of:

  1. IRendererPropertyPage.ClassID, IRendererPropertyPage.RendererClassID, IPropertyPageContext.CreateCompatibleObject for the property page class.

  2. IPersistStream.GetClassID, IPersist.GetClassID for the renderer.

There is a cleaner way to do that, called COM aggregation. Query interfaces are pointed to the inner instance automatically so that you do not need to implement them on the outer instance (unless you want to override them). Also, COM aggregation ensures that should the author of the inner class add new interfaces in a future release, your outer class will support them as well. Unfortunately COM aggregation can be done only in C++, it's not (as far as I know) possible in .NET runtimes 1.1 or 2.0. There are some new features for custom COM interface querying (which should make COM aggregation possible) in .NET 4, but I have yet to see a working sample.

  • 1
    About the COM aggregation bit, here is an example from StackOverflow on using it in .NET 4. Not much use to ArcGIS developers yet, but at least MS isn't forgetting about COM.
    – blah238
    Jul 27 '11 at 6:46
  • 1
    Yeah, we have discussed this with Kirk some time ago in context of custom features. See gis.stackexchange.com/questions/572/…
    – Petr Krebs
    Jul 27 '11 at 7:02
  • +1 For option 2, I wonder if there's some Visual Studio tool that would generate the code for this. Also, you might look at ILayerExtensionDraw if you want to decorate what OOTB Draw does. Jul 27 '11 at 14:11
  • @Kirk, when you go to implement an interface in Visual Studio, there should be an option to automatically stub out its members -- is this what you meant?
    – blah238
    Jul 27 '11 at 19:28
  • Well, I've gone through and done this (using method 2), and for some reason, it seems like the GraduatedColorPropertyPage will automatically create a new ClassBreaksRenderer that replaces mine, so this doesn't work. It works the first time through, but then the property page (via composition) "kills" the renderer I generate, which means my draw routine never gets called. Jul 29 '11 at 19:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.