Leaderboard
Popular Content
Showing content with the highest reputation on 04/12/2010 in all areas
-
You're getting an error because you're trying to cast a parent object (ElementParent) into a child object (Element). You can't do that... if the child class has some extra data or methods associated with it the parent object doesn't have any way of handling them. I made the same mistake not too long ago and AQ was kind enough to explain why it doesn't work. For your design I don't think the ElementParent class is necessary. It just makes your design harder. Labview's by-val nature makes two-way knowledge of the parent-child relationship a little harder to implement. There are a couple ways I can think of doing it; using an ElementManager class and setting up your hierarchy in memory directly as you are trying to do. (I think the recursion should work once you quit trying recurse into a different object's method. ) Conceptually I think the ElementManager is a little easier to understand since it creates a clear distinction between element behavior and element relationship behavior. For the ElementManager technique, create an Element class with the following properties and methods: Class Element Properties -string GUID // all objects must have a guid -string ElementOwner // is empty if root node -string[] OwnedElements // is empty if leaf node Methods -string GetQualifiedName -(Also add getters & setters for the class data as needed) The idea is that when an object is created at run time it generates a GUID you can use to identify it. Instead of each element storing its parents and children directly, it stores the GUID of its parent and children. Each element is completely independent and has no real knowledge of the other elements other than their GUID. To manage the relationships between the different elements, create a helper ElementManager class with the following properties and methods: Class ElementManager Properties -element[] AllElements // array to hold all element objects Methods -element GetElementByGuid(string GUID) // returns an element object Given a guid, the ElementManager will search through it's array to find the element with that guid and return that to the caller. Of course if you're going to have very large data sets you can change from an array to binary tree or any other mechanism for storing data. The array implementation is entirely private and can be changed without affecting the callers. I like to have higher level methods in my manager classes and keep GetElementByGuid private. This makes it easier to use and completely encapsulates the guid from class users. A few to consider are: -element GetParentElement(element ChildElement) // returns parent element -element[] GetChildElements(element ParentElement) // returns array of child elements -bool IsParentChildRelationship(element Parent, element Child) // returns true if Parent is a parent of Child -void AddChildElement(element Parent, element Child) // Adds Child as a child of Parent element -element[] GetElementAncestry(element Element) // Returns an array of elements from the root to the parent of this element1 point
-
Daklu, the style of my writing below is fairly terse and occassionally EMPHATIC. I've done this to emphasize key points that I think you've missed in How Things Work. Some customers in the past have felt I'm insulting them writing this way, but it is the only way I know through the limited text medium to highlight the key points. My only other option is to post just the key bits and leave out a lot of the exposition, but that doesn't seem to be as helpful when communicating. So, please, don't think I'm calling you dumb or being disdainful. I'm trying to teach. The problem is that you're almost right. Customers who are completely off-base are easier to teach because they need the whole lesson. Here, I'm just trying to call out key points, but presenting them in their full context to make sure it's clear what fits where. Throughout the post, refer to the graphic at the end of the post as it may clarify what I'm talking about. Dalku wrote: No. If there is, that's a bug that needs to be reported to NI ASAP. Think about what you just asked for... ignore the DVR part for a moment. You just asked for a PARENT object to invoke a CHILD class method. That cannot ever happen. You cannot pass a parent object directly to a function that takes a child object. The parent object in question IS NOT a child -- the parent object does not have the child's private data, nor does it have all the methods that may have been defined on the child class. For this reason, LV will break the wire if you try to wire a parent wire to a child terminal -- the wire is broken because there are zero situations in which this can successfully execute. You CAN pass a child object to a parent terminal. That is because a child IS an instance of the parent -- it has all the necessary data and methods defined to act as a parent object. What you can do is take a child wire, up cast it to a parent wire and make a Parent DVR out of that. Alternatively, you could take a child wire, make a Child DVR wire, and then upcast that to a Parent DVR wire... these two processes produce the idenitical result: a parent DVR that contains child data. Upcast and downcast DO NOT create new objects EXCEPT when they return an error. The point of a cast is to say, "I have an existing object. Please check that it is this type and approve it to go downstream if it passes this test." You use this only when you need to do something for a specific type of object and you do not have the ability to edit the parent and child classes in order to add the appropriate dynamic dispatch VIs to both. Preserve Run-time Class (PRTC) is the same thing. "Allow this object to pass downstream if it passes this test, otherwise create a new object that does pass the test." The test in this case is "Does the object in have the same TYPE AT RUN TIME as the OBJECT (not the wire) on the target object input?" If the left object is the same or a child class of the center object then there is no error. You will ALMOST NEVER WIRE PRTC WITH A CONSTANT FOR THE CENTER TERMINAL. I would say "never" because I can't think of any useful cases, but maybe someone has something out there. If you are wiring the center terminal of PRTC with a constant, something is wrong in your code. You use the PRTC to assert that the left object, which comes from some mystical source, is the right type to fulfill run-time type requirements of dynamic dispatch VIs, automatic downcast static VIs, and the Lock/Unlock of Data Value References. In all three of these cases, there is some input (either the input FPTerm or the left side of the Inplace Elt Struct) that must be passed across to the output (either the output FPTerm or the right side of the Inplace Elt Struct) WITHOUT PASSING THROUGH ANY FUNCTION THAT CHANGES THE OBJECT'S TYPE. You're free to change the object's value, but not its type. Sometimes you pass the object to functions where LV cannot prove that the type is maintained. Easy example -- pass the object into a Global VI and then read the Global VI. You'd never do this, of course, but it demonstrates the problem. LV cannot know that the object you read from the global is the same object you wrote in -- some other VI elsewhere might have written to the global in parallel. But you, as the programmer, know that there are no other writes to the global VI, so you use the PRTC to assert "this is going to be the right object type." You wire the original input (as described above) to the center terminal, and the output of the global to the left terminal, and pass the result to the original output terminal (as described above). Does that make sense?1 point