I’m in the process of updating a very large project to API 2.0, which has become more necessary now that in 2024 things like Popovers exist and they can only be opened by DesktopUIControls and not the legacy RectControls.
The structure of my project is a series of various UI classes that are EmbeddedContainerControls. The view hierarchy sometimes is 3 or 4 levels deep of embedded containers inside of embedded containers, etc.
In API 1.0, the code in a RectControl could refer to the Window property to get the container that contains the RectControl. The control could then easily iterate over the Controls list and do things with its peer RectControls. If the RectControl needed the top-level window it belongs to, it could use TrueWindow. Pretty straightforward.
In API 2.0, the code in a DesktopUIControl can get the top-level window it belongs to using Window instead. This appears to simply be a renaming of the old TrueWindow. But how do we get the window that our DesktopUIControl belongs to? It seemed obvious that the Parent property would do this, but alas, it appears that Parent points to the object one level up the the hierarchy that owns the embedded window, and not the embedded window itself.
In other words, my question is – How does a DesktopUIControl that is in an embedded window get a pointer to the embedded window itself so it can iterate over the list of Controls that reside in the same container? The Parent property does not point to the embedded window. Instead it points to an object in the view hierarchy one above the DesktopUIControl, which isn’t particularly useful, as there appears to be no elegant way to get back to the actual embedded window that API 1.0 used to simply provide as Window.
Would Self possibly work?
In a sample project, I have the following Objects:
- a DesktopContainer, Smallbox (With a button, BtnAction)
- a DesktopContainer, Mediumbox (With a SmallBox)
- a DesktopWindow (Window1) (With a MediumBox)
In the SmallBox.BtnAction Pressed Event:
Dim MyParent1 As Object
MyParent1 = Self
When I examine MyParent1 in the Debugger, it shows MediumBox.SmallBox1, and if I add logic to see the ControlCount, it is correct.
As DesktopContainer
inherits from DesktopWindow
, this is actually pretty easy. I made this short extension method that you can toss in a module:
Public Function ParentView(extends control as DesktopUIControl) As Object
var parent as Object = control.Parent
while parent isa DesktopUIControl
parent = DesktopUIControl(parent).Parent
wend
Return parent
End Function
Then call like this, in a DesktopButton.Pressed event, for example:
var parent as Object = me.ParentView
if parent isa DesktopContainer then
MessageBox( "I'M TRAPPED IN A CONTAINER!" )
elseif parent isa DesktopWindow then
MessageBox( "I'M TRAPPED IN A WINDOW!" )
end if
From there, you can cast parent
to its appropriate type – DesktopContainer
or DesktopWindow
– and iterate over the controls.
It’s important to note that since DesktopContainer
inherits from DesktopWindow
, the order in which you check the value is important if you want to distinguish between the two. If you don’t care that it’s a DesktopContainer
or DesktopWindow
then you can just cast the result of the method to DesktopWindow
then iterate the contained controls:
var parent as Object = me.ParentView
if parent = nil then Return '// Sanity check
var parentW as DesktopWindow = DesktopWindow( parent )
for each c as Object in parentW.Controls
break
next
1 Like
Here’s a version that extends DesktopContainer:
Public Function ParentView(extends container as DesktopContainer) As Object
var parent as Object = container.Parent
while parent isa DesktopUIControl
parent = DesktopUIControl(parent).Parent
wend
Return parent
End Function
And here’s a couple of methods to get Siblings:
Public Function Siblings(extends container as DesktopContainer) As Object()
var parent as Object = container.ParentView
if parent <> nil then
var result() as Object
var parentWindow as DesktopWindow = DesktopWindow( parent )
for each o as Object in parentWindow.Controls
if o <> container then result.Add( o )
next
Return result
end if
End Function
Public Function Siblings(extends control as DesktopUIControl) As Object()
var parent as Object = control.ParentView
if parent <> nil then
var result() as Object
var parentWindow as DesktopWindow = DesktopWindow( parent )
for each o as Object in parentWindow.Controls
if o <> control then result.Add( o )
next
Return result
end if
End Function
1 Like
After building a simple example project to demonstrate the issue I’m having, I have discovered that it is possible to easily iterate through the peer objects of an API 2.0 control when embedded in a container control. You just need the entire view hierarchy to be built on API 2.0 objects.
The problem I was having is that in the process of trying to “slowly” migrate a large project from API 1.0 to API 2.0, I have a “mixed” project with lots of crossover between the two APIs. I’ve got a 1.0 ContainerControl that includes both 1.0 and 2.0 objects. Although this compiles and runs just fine, the API combination appears to create a few holes.
If I’m understanding the situation I’ve created, a 1.0 control in a 1.0 container uses the Control iterators in the Window object. A 2.0 control in a 2.0 container uses the container’s Control iterators. But if a 2.0 control is in a 1.0 container the control doesn’t have a pointer to the container and the Window is the TrueWindow and doesn’t have the correct control list. (Yes, this is confusing)
Bottom line appears to be that I need to push through more significant changes to my project before things start working better. There appears to be no issue other than the realization that transitioning from 1.0 to 2.0 is a lot more complicated for large projects than it initially appeared.
Yes, you should tackle objects as a whole whenever possible. While you can mix Desktop API 1.0 and 2.0 in the same project, there will be problems if you attempt to do some things in a mixed view, as you’ve just learned.
Once you start a window/container, it’s best to just push on through and finish it.
@Anthony_G_Cyphers Great job on the solutions you’ve suggested. My problem is that my DesktopUIControl is contained in a legacy ContainerControl. The API mismatch appears to prevent being able to get a list of siblings to the DesktopUIControl.
I’m just glad you’ve found a solution to your problem.