Since Implicit Instance = Off is all the rage now I thought this would be a good time to ask this question:
Assuming Implicit Instance = Off:
What is the best way to generically create an instance of a window if it is not already in existance and if it is then move said window to the forefront?
Var t As Introspection.TypeInfo
Var strWindowName As String
Var bWindowFound As Boolean
bWindowFound = False
For each w as DesktopWindow in app.Windows
t = Introspection.GetType(w)
strWindowName = t.Name
If strWindowName = NewWindowName Then
bWindowFound = True
End If
Next
I figure that the next bit of code is something like:
If bWindowFound = False Then
// Struggling to figure out what could should be put here so that the requested window is created
// I know that: Var w as New winWindow will do this, but I think you have to explicitly use the name. I am trying to figure out how to pass the name and it create the new instance
Else
NewWindownName.Show
End If
So Implicit Instance is just an additional module, function, and property. Something like this pseudo code:
Module Window1
Global Class Window1
...
End Class
Global Function Window1() As Window1
If mInstance Is Nil Then
mInstance = New Window1
End If
Return mInstance
End Function
Private Property mInstance As Window1
End Module
You can setup much of the same logic with shared methods and properties, while giving you a little more control:
Class Window1
Shared Function SharedInstance(Create As Boolean = True) As Window1
If mInstance Is Nil And Create = True Then
mInstance = New Window1
End If
Return mInstance
End Function
Event Closing()
If Self = mInstance Then
mInstance = Nil
End If
End Event
Private Property mInstance As Window1
End Class
Now you would call Window1.SharedInstance.DoWhatever instead of just Window1.DoWhatever. This makes it hard to accidentally call the wrong instance, and allows you to pass False into Window1.SharedInstance if you want to NOT create an instance if one doesnât already exist.
This is called a Singleton model and if itâs what you need, implicit instance isnât necessarily a bad thing. In the rare cases I need a singleton window - such as a preferences window - I use a model like this, but I wouldnât call somebody wrong for using implicit instance instead. It has its uses.
As for doing it generically⊠donât. Iâve had too many problems with introspection of the years. It works great until it doesnât, and then your code behaves in the most bizarre ways.
Perfectly. I do it like this. We will assume the ââAboutâ window here.
Var myAbout as AboutWindow
âWe will store the loop bound in a variable first
âBetter than re-evaluating each time through the loop
Var limit as integer = app.WindowCount-1
For x as integer = 0 to limit
If app.WindowAt(x) isa AboutWindow then
myAbout=AboutWindow(app.WindowAt(x))
âBreak the loop since we found it
Exit
End if
Next
âCreate the instance if it wasnât there
if myAbout=nil then myAbout=New AboutWindow
MyAbout.Show
Future Jerry: Re-reading your original post, I more fully understand your desire for a âgenericâ method, whereas my code is not that. So now youâve given ME something to play with
Mostly, yes. As I said, I personally prefer controlling the singleton myself, using an accessor that is clear. But itâs so similar to implicit instance, that I wouldnât fault somebody or even recommend against using implicit instance.
When you structure your code to remove all possible globals and treat every project item as a mini program, controlling the accessor like this makes a lot of sense. Window1 is always the class name, and Window1.WhateverINamedTheAccessor is always the accessor. Thereâs no ambiguity. I took away the global Window1 function without taking away the functionality it provides.
Whatâs wrong with having a property, e.g. in the App class (SingleWindowInstance as MyWindow) and having a function like the following one?
Function GetSingleWindow as MyWindow
if SingleWindowInstance=nil or SingleWindowInstance.SomeControl=nil then
'Window either doesn't exist or was closed
SingleWindowInstance=new MyWindow
end if
return SingleWindowInstance
end function
Or maybe Iâve not understood the question correctly .
I mean⊠itâs an option. Not exactly well organized, but itâs an option. Itâs usually better practice to keep factory methods like this with the class itself.
I do this with a Shared Method and a static variable:
Public Shared Function GetSharedInstance() As SomeClass
static sharedInstance as SomeClass
if sharedInstance=nil then
sharedInstance=new SomeClass
end
return sharedInstance
End Function
The Constructor for SomeClass is Private so the class canât be created without going through the shared method.
It is considered bad design. It will retain the object indefinitely in a hidden global scope, no accessors. That means that the obj reference only can be released at App.Close() time, not before.
And yet, there are times when this is perfectly acceptable, which is why I use it.
But you bring up a good point, so here is a revision that addresses those concerns. Once the instance is no longer in use by the external code, it is destroyed and the WeakRefâs value is nil.
Public Shared Function GetSharedInstance() As SomeClass
static sharedInstance as WeakRef
if sharedInstance.Value=nil then
dim newInstance as SomeClass
newInstance =new SomeClass
sharedInstance=new WeakRef(newInstance)
end
return sharedInstance.Value
End Function
Class MyWindow Inherits DesktopWindow
Private Shared Property SelfInstance As MyWindow
Public Shared Sub Instantiate()
If SelfInstance = Nil Or SelfInstance.Handle = Ptr(0) Then
SelfInstance = New MyWindow
End
End Sub
Public Shared Function GetInstance() As MyWindow
Instantiate
Return SelfInstance
End Function
Public Shared Function PeekInstance() As MyWindow
// Return current ref without a new instantiation, even a nulled one
If SelfInstance <> Nil And SelfInstance.Handle = Ptr(0) Then SelfInstance = Nil // if closed, free it
Return SelfInstance
End Function
Public Shared Sub ReleaseInstance()
If SelfInstance = Nil Then Return
If SelfInstance.Handle <> Ptr(0) Then SelfInstance.Close // if existing, try to close it
If SelfInstance.Handle = Ptr(0) Then SelfInstance = Nil // if closed, free it
End Sub
End Class
Fast immediate approach without needing events, in Xojo, after closed, before released, the handle is nulled, you potentially can find a not Nil Window but invalid, I avoid invalid ones to avoid exceptions.