Accessing ContainerControl / EmbeddedWindowControl Type

I have created a container control called myCustomCC with a couple of controls in it and placed it in a window.

I then iterate through all the window controls using “Window.ControlCount” loop and identify the control using “IsA EmbeddedWindowControl” but what I can’t figure out is how to find out whether this particular EmbeddedWindowControl is myCustomCC because its name is a complex “wrapper” verison of the actual control name on the window (not the original container control name) and I can’t use “IsA myCustomCC” because this does not work.

I need to know it is specifically a myCustomCC (and not some other custom container control type on the same window) so I can call a custom method on it etc.

Any ideas?

It’s not enough to use IsA, you have to then cast it.

if ctl IsA myCustomCc then MyCustomCC(ctl).methodName() End If

Even though I have identified the control IsA EmbeddedWindowControl Xojo is not then allowing me to cast it to a specific type (myCustomCC) and gives me an illegal cast exception. And I don’t know how to find out the type either since there could be two types of container controls on a window.

The name is probably _wrapper_ myCustomCC. What I would do is to verify the name with

if instr(control(i).name, "myCustomCC") > 0 then 

As Greg said, when you are sure it is myCustomCC, you must cast it to access its methods.

Thanks, Michel, yes I am using Instr to access the name value right now but that’s not ideal and as mentioned, I cannot cast it due to IllegalCastException. Instead I have to refer to the control by its actual name in order to access the cc methods.

This is also not ideal since I have ten controls like that so have to manually call the same method one by one using If and then etc rather than casting and calling it once.

You cannot cast an EmbeddedWindowControl to anything. There is no direct way to access the containercontrol from the Control() method. It’s best to maintain your own array of containers. Barring that, you can iterate over all the objects in Runtime and find the one that matches your embeddedwindowcontrol. I recommend maintaining your own list of them.

your best off NOT to reach inside a container at any rate

put methods on the container that you can call that does whatever work is needed
then even if the guts of the cc changes (you change controls names etc you can just change the code in the exposed method and things continue working)
treat them like black boxes - you know nothing about their innards & have to use the API they provide (which of course you also get to write)
it will make your life simpler in the long run

[quote=321461:@Norman Palardy]your best off NOT to reach inside a container at any rate

put methods on the container that you can call that does whatever work is needed
then even if the guts of the cc changes (you change controls names etc you can just change the code in the exposed method and things continue working)
treat them like black boxes - you know nothing about their innards & have to use the API they provide (which of course you also get to write)
it will make your life simpler in the long run[/quote]
I have created methods on the container control to access but what I’m trying to say is that when I loop through the windows controls and identify an EmbeddedWindowControl how can I identify what type of container control it is (other than Instr name method) in order to call a method on it and even then I still have to manually call the actual control and method since it can’t be cast to anything…right?

So let’s say I have five container controls in a window and I loop through and want to call the same method on all five of them, right now I have to use ccname1.execute(), ccname2.execute() and so on. Is there an easier way rather than hard-coding each control call?

this method will give you all the containercontrols inside a given window:

[code]Public Function ContainerControls(extends w as Window) as ContainerControl()
'get a list of all the container controls in a window

dim theList() as ContainerControl
dim o as Runtime.ObjectIterator = Runtime.IterateObjects

while o.MoveNext
if o.Current isA ContainerControl and ContainerControl(o.Current).Window is w then
theList.Append ContainerControl(o.Current)
end if
wend
return theList

End Function
[/code]

but it is not very efficient as it loops throught all the objects at runtime, this can be quite long on a heavy project.
a better way is to use the notification interface (look about it in the dev center)
at the open event of the window, register all your containercontrols inside an array of the window, then you can call them from a window’s method.

[code]Dim ccs As New Dictionary()

Dim iterator As Runtime.ObjectIterator = Runtime.IterateObjects()
Do Until Not iterator.MoveNext()
If iterator.Current IsA ContainerControl Then
Dim cc As ContainerControl = ContainerControl(iterator.Current)
ccs.Value(cc.Handle) = cc
End
Loop

For i As Integer = 0 To ControlCount - 1
If Control(i) IsA EmbeddedWindowControl Then
Dim handle As Integer = Control(i).Handle
Dim cc As ContainerControl = ccs.Lookup(handle, Nil)
If cc <> Nil Then
// Do something with cc…
End
End
Next[/code]

There is a simpler way : store references to the CC when they are instantiated. In their Open event for instance. Can be done in a dictionary or an array.

Then you cycle through the dictionary or the array, not the window.

1 Like

It would be great if EmbeddedWindowControl had a (read-only) property AsContainerControl to return the ContainerControl instance.

Okay but even with a dictionary or array of all container controls in a window how can you identify the “type” and how can you call a specific method based on that specific type? So do ccType1.Execute() and ccType2.Flush() whereby Execute is a method specific to type 1 cc and Flush is a method specific to type 2 cc. I’m guessing you can’t because you can’t cast a type like ccType1(cc).Execute and ccType2(cc).Flush is probably not possible so you still have to go by individual control names and method calls for each one by name.

Once you have the container control instance you can cast it to ccType1 or ccType2.

IsA

if cc isA CC1 then
elseif cc isa CC2 then
end if

How many kinds of CC do you have ? You could have a dictionary or array for each type, or do what Norman shows above.

[quote=321518:@Norman Palardy]IsA

if cc isA CC1 then elseif cc isa CC2 then end if [/quote]
Ahh, I see. I will try all that out. Thanks.

The problem with this is that I cannot write generic functions accessing all controls in a Window this way, though, if the window contains ContainerControls.

E.g, I want to write a general function that finds all editable controls in a Window and sets their Enabled property to false - it won’t be able to find controls inside CCs unless I explicitly pass those CCs to the function as well. Not very clean, IMO.

I agree with Eli that EmbeddedWindowControl should provide an accessor to the ContainerControl or provide access to the Controls inside.

Not to resurrect an old topic :wink: But I’m going to resurrect an old topic.

Has anyone found a way around this in the meantime? I am trying to write a generic window extension that will let me do some changing of the tab order of things as I am creating much of the interface dynamically and cannot trust the information used for that to be in the proper tab order. I wish to walk every control on the window, including ones embedded on container controls but that seems to be impossible as the EmbeddedWindowControl object is undocumented, opaque and has no .controls method or obvious other way to walk it’s control array. It cannot be cast back to a ContainerControl or anything else as far as I can tell.

I’m going to have to write specific methods for all the affected windows that use local container control references and know what they should be which is a pain as it really should be possible to find all the controls that are currently on a window even if some of them are inside a container control.

Walking the entire object list for the entire program is not an option in this case as it’s a large program and there are millions of objects at runtime.

Protected Module EmbeddedWindowControlExtensions
		Function Container(extends ctrl as EmbeddedWindowControl) As ContainerControl
		  Dim handleToFind As Integer = ctrl.Handle
		  
		  If handleToFind = 0 Then
		    Return Nil
		  End If
		  
		  // ok we have the handle for this EWC 
		  // so find the matching ContainerControl
		  
		  Dim iter As Runtime.ObjectIterator = Runtime.IterateObjects
		  While iter.MoveNext
		    If iter.Current IsA ContainerControl Then
		      Dim tInfo As Introspection.TypeInfo = Introspection.GetType(iter.Current)
		      Dim pInfo() As Introspection.PropertyInfo = tInfo.GetProperties
		      For Each propInfo As Introspection.PropertyInfo In pInfo
		        If propInfo.Name = "handle" And propInfo.Value(iter.Current) = handleToFind Then
		          Return ContainerControl(iter.Current)
		        End If
		      Next
		      
		    End If
		    
		  Wend
		  
		  Return Nil
		  
		End Function

End Module