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.
It’s a hard link back in Xojo 13r4.1.
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.
It is an implementation detail that has leaked out
I’d expect it to disappear
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)
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.
Add an event to return the window, which must be implemented by instances.
don’t have a control yet… just a class.
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.
or sign this request to make it an official read-only property: <https://xojo.com/issue/45698>
Here’s that third way. Pass it an object and it returns the window the object lives on.
[code]Function getWindowOfTarget(target As Object) As Window
if target = nil then return nil
dim tti, wti As Introspection.typeInfo
dim wmia(), mi As Introspection.MethodInfo
dim w As Window
tti = Introspection.GetType( target ) //target typeinfo
for i As integer = 0 to WindowCount - 1
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
Can’t get it to work Will. Never had a match here
Hmmm, works for me on Mac Desktop. Not extensively tested and wouldn’t work with Control Sets, just a template to be explicit about the idea.
To test I created a Class, Class1, and dropped an instance on a window to make Class11.
Then in a PushButton
[code]dim w As Window = getWindowOfTarget( Class11 )
if w = self then success else fail[/code]
Tested other variations too to confirm I’m not getting false positives.
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 )
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!
The function is
Function Window() as Window
and you should find that it gets you exactly the right thing
Thanks, Norman! Works like a charm!
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)