Sometimes it is a good idea to break your running code and watch the debugger. I just noticed that a control based on a general object has a computed property ownerWindow which is a WeakRef of the window it is connected to. Which is absolutely great, but its not accessible. The compiler doesnt know it, and the LR too.
I can probably peek into it with Introspection (havent tried yet), but before I try: Since when does this property exist? I havent found anything about it. And would it be possible to make it accessible without introspection? Its an amazingly useful property for custom controls without visual representation.
I’d recommend against building on undocumented aspects. It used to be that Introspecting a Pair (an immutable object) revealed properties _Left and _Right which could be mutated. A couple versions later those properties are no longer listed in Introspection. Same could happen with ownerWindow unless it gets documented, though it is currently listed and modifiable via Introspection.
Oh sh.t ! I am running code in the contructor of an object for finding the reference to the parent (window) , using ‘ownerWindow’ and did not realize that it could be about to disappear.
// find reference to the containing window (Me)
Dim props() As Introspection.PropertyInfo = Introspection.GetType(Me).GetProperties
For Each p As Introspection.PropertyInfo In props
If p.Name = "ownerWindow" Then
Dim wr As WeakRef = p.Value(Me)
Dim objParent As Object = wr.Value
If objParent IsA Window Then ParentWindow = Window(objParent)
Exit
End If
Next
It works fine, but tricky since it’s an undocumented feature. No guarantee.
What would be the alternative ?
Make it a subclass of Control, then you can use it’s Window property.
or
Add an event to return the window, which must be implemented by instances.
or?
You can still make it a subclass of Control. I think it makes sense because you want some features of that class for yours.
Another way is to loop over all windows and use Introspection to look at all of it’s properties to find the one that matches self. Haven’t tried this though, not sure where a non-control instance will appear.
w = Window( i )
wti = Introspection.GetType( w ) //window typeinfo
wmia = wti.GetMethods //window methodinfo array
for q As integer = 0 to wmia.Ubound //for each methodinfo of window
mi = wmia( q ) //grab methodinfo
if mi.GetParameters.Ubound = -1 and mi.ReturnType <> nil then //follows form
if mi.Invoke( w ) = target then return w //success if instances match
end
next
If you work direct on a window, as you show above, it works. No issue.
If you drop an instance of Class1 in a containercontrol, add a pushbutton to the CC too, and in the action you do:
[code] dim w As Window = getWindowOfTarget( Class12 )
break[/code]
the result stays Nil because of no match.
Within Class1 i still need a reference to the Window the CC holding Class1 sits on.
BTW: it’s not a big deal to add a property to the class and just pass the reference, but in order to make it more universal and convenient I build it this way. But … "ownerwindow’ WILL disappear, Norman just said… I suggested to turn the “bug” into a feature, but nope.
Add an event to your Class - ContainingWindow - that your instances you drop on the window implement
Events can return values and you can call them just like normal functions
The feature request to make the property a valid one was closed because Window() is supposed to do the same. Which I still dont understand I found no way to get the index of the window thats opening automatically. Or could one consider that it will always be Window(WindowCount-1) because it must be the window that was added last?
I think the best idea would be to add a fallback to Wills method that examines the subviews/controls of the window too if it did not find any match. For my purposes, where an invisible object is added to the window layout, Wills proposal should do fine. Thanks a lot!
using xojo.Introspection
Dim info As TypeInfo = GetType(me)
Dim methods() As MethodInfo = info.Methods
for q as integer = methods.Ubound downto 0
dim p as MethodInfo = methods(q)
if p.Name = "Window" then
dim w as window = p.Invoke(self)
return w
end if
next