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.
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.
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.
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.
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.
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 But Im 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 its control array. It cannot be cast back to a ContainerControl or anything else as far as I can tell.
Im 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 its 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