ownerWindow WeakRef?

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 – it’s not accessible. The compiler doesn’t know it, and the LR too.

I can probably peek into it with Introspection (haven’t tried yet), but before I try: Since when does this property exist? I haven’t found anything about it. And would it be possible to make it accessible without introspection? It’s 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)
      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?

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

  end
  
next

next

return nil

End Function[/code]

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 )

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 don’t understand – I found no way to get the index of the window that’s 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 Will’s 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, Will’s 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

Try it

Thanks, Norman! Works like a charm!

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