How to set FixedAspectRatio to False for Legend

2715
17
06-25-2014 08:50 AM
TimWhiteaker
Occasional Contributor II
I'm creating a legend. I want to set IBoundsProperties.FixedAspectRatio to False. When I run the code, I get "The method or operation is not implemented."

Code snippet (C#):
ILegend2 legend = mapSurroundFrame.MapSurround as ILegend2;
IBoundsProperties bounds = legend as IBoundsProperties;
bounds.FixedAspectRatio = false;


I get the same error if I cast to IBoundsProperties from the mapSurroundFrame object instead of the legend object.
0 Kudos
17 Replies
RobertMaddox
New Contributor III
CoClasses "implement" the behavior defined by the Interface. 
Interfaces only define a contract, there is nothing between the curly braces, i.e. no implementation.


:rolleyes:

I am not going to get into some silly academic debate about the word "implement". I am a programmer by trade, not a GIS person, so I understand completely how interfaces work and don't need the idiots guide link to MSDN, Thank you very much. The point was that there was a property on the interface which means that the property must exist on any class that implements the interface. Whether there's anything "between the curly braces" in the source code or not is completely irrelevant because for all we know, they could be auto-properties. (Here's a link to MSDN for you: http://msdn.microsoft.com/en-us/library/bb384054.aspx)

It is correct to use Interface types as reference variables, but what I was trying to tell the original poster is that you cannot expect to assign Interface types to Interface types and expect to call a method that is only implemented on one of the CoClasses.  I was hoping that by reading this he would know how to fix his problem. He needs to instantiate an instance of whatever CoClass he wants and assign it to an Interface.  He was trying to get a Legend by calling some method that returns an Interface and then assign that Interface to his IBoundsProperty Interface and then he didn't know why he couldn't call FixedAspectRatio.


Well, I don't know how much success you had with the OP in that, but that point was clearly lost on me. Why couldn't you have written some sample code to illustrate the proper way of doing it?

Ironically though, you want to know what the concrete class for ILegend is actually named? LegendClass_2. Because there's an ILegendClass interface with a LegendClass pseudo-class (with its concrete class being LegendClassClass), so they had to append a "_2".

The other thing about this is that many times when working with ArcObjects, you don't want to create new objects, you want to get the things that are already on the map. So if the OP's legend is already loaded on the Map, what good is it going to do to call new LegendClass_2()? Also, many classes can not be created and others have no public constructors. In those cases when you need to create a new one of those, you typically have to use a factory of some kind, and the signatures on those factories frequently just specify a return type of object, IObject, or some other useless type that has to be cast to a usable interface type before you can do anything with it.

What do you expect to happen here?



  1. The interface is not designed to be implemented outside of ArcObjects. For example, there's no reason a developer would have production code that would implement the IGeometry interfaces. The only case I can imagine when anyone would ever want to implement those interfaces would be when doing headless unit tests, but that would obviously not be production code.

  2. The new functionality is going to be added to all of the classes that implement the previous interface.


If both of those are true, then I expect them to just add the functionality to the existing interface.

I don't know about "half the time".  Do you have a specific example of on which Interface that happens?


Sure. ICalculatorUI2 (http://help.arcgis.com/en/sdk/10.0/vba_desktop/componenthelp/0022/002200000013000000.htm), the reason I joined this forum two weeks ago, which is still a problem for me. It doesn't inherit from ICalculatorUI, even they are only different in one property that was added to ICalculatorUI2. And they are both implemented only by CalculatorUIClass, and there's no reason anyone would have a custom implementation.

Bottom line to all this, I'm glad the OP was able to figure it out on his own. It clearly wasn't a type casting problem as he would have gotten a NullReferenceException, not a NotImplementedException, though I don't really expect someone who doesn't know C# to know that. But I don't really see how quibbling over whether an interface implements a property or simply defines it is really helping anyone. Any object that can successfully be cast to an interface typed variable MUST have all of the members of that interface implemented, regardless of whether the implementation happened in the object's class or in a base class three levels up. It doesn't matter, so it isn't worth talking about.

BTW Java programmer, did you not know that in the latest version of Java, interfaces CAN implement methods? (http://www.techempower.com/blog/2013/03/26/everything-about-java-8/) One of the reasons for this change was to make it easier to add members to interfaces that are already in production. Pretty cool, huh? 😉
0 Kudos
LeoDonahue
Occasional Contributor III
>>The point was that there was a property on the interface which means  that the property must exist on any class that implements the interface

You are correct.  Not only must it exist, but the functionality must be provided by the class that implements the Interface, not within the Interface itself.

Your auto-properties example works on classes, not Interfaces.  Interfaces are abstract and only define method signatures.  You can't instantiate an Interface, so if there was some kind of functionality provided by an auto-property inside an Interface, you would be breaking the nature of an Interface. 

>>Why couldn't you have written some sample code to illustrate the proper way of doing it?
Because the forums shouldn't be vending machines for code samples.  Why can't I answer the question the way I want to?

The Original Poster did this:
ILegend2 legend = mapSurroundFrame.MapSurround as ILegend2; 
IBoundsProperties bounds = legend as IBoundsProperties; 
bounds.FixedAspectRatio = false;


mapSurroundFrame.MapSurround returns an Interface type, not an instance of a CoClass.  He is essentially assigning an Interface reference to another Interface reference.  Nothing wrong with that at this point, if they were related.

Then he assigns the variable bounds (which is an Interface type) a reference type of legend.  "legend" is a type of ILegend.  Now he has two object references pointing to the same object, whatever it is. 

Using the .NET docs:  There is no FixedAspectRatio property on the ILegend Interface:
http://help.arcgis.com/en/sdk/10.0/vba_desktop/componenthelp/000t/000t00000775000000.htm

I don't know why you want to make it sound like I'm quibbling, it is just a fact.  Quibble about it all you want.  But at the end, he got a NotImplementedException because he assigned an Interface type (ILegend) which does not implement or even define FixedAspectRatio to a reference variable type of IBoundsProperties which does.  The compiler is going to check the actual type of the reference and tell you: "hey, FixedAspectRatio is not implemented on the object type you have currently".

I disagree with you on the IGeometryInterface.  Why couldn't it be possible for someone to create their own special geometry class that wants to provide implementation for the methods defined in the IGeometryInterface?  Just because you don't do it, doesn't mean someone else might not want to.

You can define constants in Java Interfaces now and people abuse them.
0 Kudos
RobertMaddox
New Contributor III
Your auto-properties example works on classes, not Interfaces.  Interfaces are abstract and only define method signatures.  You can't instantiate an Interface, so if there was some kind of functionality provided by an auto-property inside an Interface, you would be breaking the nature of an Interface.


I was merely talking about the "nothing between the curly braces" comment because auto-properties have nothing between the curly braces and look exactly like a property definition on an interface: `public bool FixedAspectRation { get; set; };` That's it. A complete no-code implementation.

Because the forums shouldn't be vending machines for code samples.  Why can't I answer the question the way I want to?


Not saying they should be or that you can't do whatever you want. Just saying that code samples are more helpful than abstract comments about programming. "A code sample is worth 1024 words!" -Me 😉

But at the end, he got a NotImplementedException because he assigned an Interface type (ILegend) which does not implement or even define FixedAspectRatio to a reference variable type of IBoundsProperties which does.  The compiler is going to check the actual type of the reference and tell you: "hey, FixedAspectRatio is not implemented on the object type you have currently".


Actually, you're wrong. First off, it wouldn't be the compiler because it's happening at Runtime and because the compiler by definition could never know whether or not two interfaces could be implemented by the same class or not. (Now who's quibbling, right? LOL ;))

The other reasons get to the point of why I said I didn't really expect a non-C# programmer to understand it. First of all, the NotImplementedException is never thrown by the CLR. It is in fact a lazy man's implementation. (See this topic on SO: http://stackoverflow.com/questions/410719/why-does-notimplementedexception-exist)

Also, with the code `IBoundsProperties bounds = legend as IBoundsProperties;`, bounds will either be an object of a type that implements IBoundsProperties, or it will be null. If the code was written as `IBoundsProperties bounds = (IBoundsProperties) legend;` then you would get an InvalidCastException if the cast failed. The `as` operator is the conditional cast operator in C# and it will first check to ensure that the cast is valid before doing it and if it isn't valid, then it will return null. That's why I said that that it would have been a NullReferenceException if the object in question did not implement either ILegend2 or IBoundsProperties.

I will also say though that, even though the casting from IMapSurround to ILegend2 was not a safe cast and should have been tested for null to make sure that the casting worked, the casting from ILegend2 to IBoundsProperties was completely safe since we know from the docs that the only class that implements ILegend2 is LegendClass_2 (http://help.arcgis.com/en/sdk/10.0/vba_desktop/componenthelp/index.html#/LegendClass_Class/000t00000...) and that class also implements (though poorly, as this case has shown) IBoundsProperties. Therefore, it would not be necessary to test for null after this cast. And even though that could change in a later version, you'll still have to deal with issues when moving to a new version no matter what.

I disagree with you on the IGeometryInterface.  Why couldn't it be possible for someone to create their own special geometry class that wants to provide implementation for the methods defined in the IGeometryInterface?  Just because you don't do it, doesn't mean someone else might not want to.


Well, you're free to do whatever you want... But when dealing with real world ArcGIS programming, why would you ever want to? You couldn't assign any of your MySpecialGeometry objects to a feature, nor could they be drawn on the map. So what's the point?

You can define constants in Java Interfaces now and people abuse them.


You can do that too, but I was talking about the default method implementations where you can write out the code for methods that are defined in the interface. Thus your class wouldn't have to provide an implementation for that method when it implements the interface. Would you consider that to be "breaking the nature of an interface" as you stated auto-properties in an interface would be? I know it's a hotly debated issue in some circles, but I personally think it's a pretty cool idea that gets rid of a lot of boilerplate code and annoying tedium in Java. Next they just need to add true properties instead of having getters and setters everywhere. 😉
0 Kudos
LeoDonahue
Occasional Contributor III
Robby,

Every once in a while I get into conversations like these.  It usually starts and ends the same way every time where someone wants to get in a word battle with me over what did you call it - academic meanings?  I'm just using the standard language that is out there and I always run into people who what to use a different language (not programming language) in which to communicate.  If you have a better word for my use of the word "implement" for classes that need to provide the guts to the method signatures in Interfaces, let me hear it.  I'd be glad to consider to start using it.

I'll agree to comment on the last paragraph where you asked my opinion about the Java 8 feature of default methods in Interfaces.

I think if people "want" to add default methods to Interfaces, then maybe they should be looking at extending an Abstract Class for that instead.  Abstract Classes can have "implementation" code in their methods.  And, since you can re-declare and re-define the default methods in Interfaces, what would be the point?  You would be breaking the intent of having a default method in Interfaces in the first place. 

But... with default non-abstract methods in Interfaces I can see where you gain the ability to have Abstract Class behavior without needing to declare "your" class as Abstract.

I would be interested to know what "use cases" there are that have been championing this change in Java 8.  I know, Lambda expressions.

And to be fair, this new feature is a way to provide other new features without breaking the Collections API.  So I don't know what to think about it, really.
0 Kudos
RobertMaddox
New Contributor III
Every once in a while I get into conversations like these.  It usually starts and ends the same way every time where someone wants to get in a word battle with me over what did you call it - academic meanings?  I'm just using the standard language that is out there and I always run into people who what to use a different language (not programming language) in which to communicate.  If you have a better word for my use of the word "implement" for classes that need to provide the guts to the method signatures in Interfaces, let me hear it.  I'd be glad to consider to start using it.


I must admit that I'm not sure what exactly this is in response to in my last message. It would fit much better as a response to previous messages, though as I recall, I made a similar statement about having a "silly academic debate about the meaning of the word 'implement'". I don't really think that's what's happening though as I've already conclusively proven that the cast to IBoundsProperties was successful and thus both the ILegend2 and IBoundsProperties interfaces (and thus all of their members) were in fact implemented by the OP's object. So I think we are in agreement over the meaning of the word in this context.

The only possible point where we could disagree about this at this point would be if you argued that a class that implements a property by causing it to throw a NotImplementedException (which is what Visual Studio does when it stubs them out) is not actually implementing the property or interface. While true that it is not a useful implementation and should never happen in production code, it isn't true from the perspective of the programming language itself. Nor is it something that can ever be tested for, like you can test whether or not an object implements an interface. It could only be discovered by attempting to use that property and catching the exception. Documentation could also help, but I haven't found anything in the docs that mention anything about this property being unsupported for legends like what I found for ILabelEngineLayerProperties in another thread (http://forums.arcgis.com/threads/114312-how-to-obtain-ILabelEngineLayerProperties2-and-error-calling...) - which should have been handled with a NotSupportedException, not a NotImplementedException.

Now, I tried to reproduce the issue that the OP was having, but I couldn't get it to throw an exception. I also couldn't get it to work either though, FixedAspectRatio remained true even after setting it to false. I am running on 10.1 though, so perhaps they changed the implementation between 10.0 and 10.1. *shrugs*

I think if people "want" to add default methods to Interfaces, then maybe they should be looking at extending an Abstract Class for that instead.  Abstract Classes can have "implementation" code in their methods.  And, since you can re-declare and re-define the default methods in Interfaces, what would be the point?  You would be breaking the intent of having a default method in Interfaces in the first place.


One thing about abstract classes though is that sometimes you don't have the option of choosing what you inherit from. For example, if I wanted to add a function BlinkingText to certain controls, like TextBoxes and Labels which would cause their text to blink for 3 seconds and then I also wanted it to work on my Form so that the title of the form would blink, there's no where in the inheritance hierarchy that I could put an abstract class that all three of those could inherit from. If however I could define an interface that says that it has a Text property (which all three classes have already) and then defines my function with a default implementation that causes the Text to blink for 3 seconds, then all I would have to do is add that interface to my classes that inherit from those three classes and everything works. Now, I can already achieve this simple functionality in C# using extension methods, but this was just a simple example to illustrate the inheritance hierarchy problem, which can't always be handled as easily.

Regardless, I've enjoyed our discussion (despite a couple rocky points) and I hope you have too. 😉
0 Kudos
TimWhiteaker
Occasional Contributor II

I just tested in 10.1 and had the same result as Robert: No exception was thrown, but FixedAspectRatio remained true even after setting it to false.  However, I also found that the legend was able to adjust its width and height properties correctly without my intervention, so my solution of programmatically updating the size of the element containing the legend is no longer necessary in ArcGIS 10.1.

0 Kudos
RobertMaddox
New Contributor III
Leo, my man. I was just trying to help out tomalley23 on his question and found out he's using Java ArcObjects. That led me to go to the docs and now I understand why you were so insistent to begin with that the OP create a new object! LOL

Apparently you can't get an actual Workspace from an IWorkspaceFactory and you have to do something like this example from the docs:

IWorkspaceFactory rasWkspFactory = new RasterWorkspaceFactory();
IWorkspace wksp = new RasterWorkspace(rasWkspFactory.openFromFile(aPath, 0));


That is so unbelievable! LMAO

Seriously glad I don't have to do stupid stuff like that. You deserve some serious props, man. I thought to begin with that it was just a philosophical dislike for working with interfaces all the time in ArcObjects and you just hadn't gotten into the whole mentality of how ArcObjects is designed. But now I see that the Java ArcObjects is this crazy stupid thing where you'll get an exception if you just use `IWorkspace wksp = rasWskpFactory.openFromFile(aPath, 0);` even though the docs say that openFromFile returns an IWorkspace! WTF! It seriously blows my mind! LMAO

My coworkers must think I'm losing my mind right now cause I've been laughing so hard.

Anyways. Would you mind taking a look at tomalley23's question? I know I can't help him out with that at this point. And I'm going to make sure to state on my resume next time I'm looking for a job that even though I know Java and I know ArcObjects, I do NOT know Java ArcObjects! 😉

Good times, buddy. :cool:
0 Kudos
LeoDonahue
Occasional Contributor III

>>Would you mind taking a look at tomalley23's question?

Can you help me find it in this new forum?  I don't remember the title of that post.

0 Kudos