I know I’ve used this logic previously, but in the latest Xojo, simply comparing a variable named TopWindow against a window using = causes the value assigned to the TopWindow to change to the compared value …
In code in a window named WMain:
TopWindow = Me // assigns TopWindow to WMain
In a global method called later (I’ve verified that TopWindow is pointing to WMain going into this):
if TopWindow = WWizard Then // check against another window
This SHOULD be returning False and instead is now causing TopWindow to point to WWizard instead of WMain and the If resulting in a True condition. On the other hand, If I use:
If TopWindows <> WMain Then // achieves the same result
The TopWindow assignment stays set to WMain instead of changing and the If gets the proper condition result.
It appears that using = as OperatorCompare instead of Setter is not working and the = is only being used as a setter.
maybe use IS instead of =
and whats “topWindow” declared as ?
Is WWizard an implicit instance ?
Simply referring to it this way will cause it to show & become “topmost” and so topmost appears to change - that is assuming that topmost is a computed property
but without more context cant really tell
If in doubt mock it up in a simple project, this doesn’t happen even with a simple computed property (as it shouldn’t), so the only thing I can think of is that you’ve implemented something to cause this to happen.
system.DebugLog(str(TopWindow = WWizard)) 'False
If TopWindow = WWizard Then
'Never get in here
'TopWindow is still WMain here
'TopWindow is still WMain here
remove the debuglog though as that may cause the implicit instance to get created before the rest of the code runs
its really easy to set things up in a way that doing a comparison like this causes some other code to run that changes the window stack and what is the “top most window”
esp if TopMostWindow is computed and not a locally dim’d variable that holds a reference
without knowing more about tims code its hard to know what the cause may be though
TopWindow is a Global Dim’d variable:
Dim TopWindow As Window
And it’s changed as the Window in use changes rather than depending on something like Window(0)
Use in the code is so that a global method knows which window to update - like:
If TopWindow = WWizard Then
Following the TopWindow variable through this code when TopWindow = WMain (and there are no threads running), resulted in TopWindow changing as soon as the If line is executed. Now that I’m checking each call in an If block, I’m seeing this regardless of whether I’m calling “=”, “<>”, or “Is”, and it only occurs if WMain is the active window and the TopWindow is set to the WMain window and the check is in reference to the WWizard window.
In each case, when stepping through the code, any check for TopWindow against WWizard results in WWizard opening and the value of TopWindow being reset. Because I open one or the other of these dependent on user preference for starting mode, the App class has no default window assigned, but both of the windows are implicit. Both windows are normal Document windows. Checks against WMain when WWizard is TopWindow do not result in WMain being re/opened.
maybe add break point to each of those windows constructors & open events ?
that might give you a clue
also turn TopWindow into a global computed property and put a break in the setter
Thanks, Norman - that was my first outing into this frustration The break in the setter simply pointed back to the If test in the calling event/method …
Okay - migraine time here.
Let me rephrase this into a request for a suggestion -
Given a Window layout where a user may chose to have either a Wizard-stype interface or a more advanced style interface displayed at launch.
When other code is executed that may open MessageDialogs, SaveAsDialogs, or other windows that need to reference back to the users’ original choice of mode, how can I set a property that will always track the proper master window?
As described above - I had been setting up a Global property named “TopWindow” and in App.Open showing either the Wizard or Main window. During operation, I used “TopWindow” to provide the anchor for MessageDialogs, SaveAsDialogs, other Windows, and reset functions to return the user to their specified work environment.
I did more digging and the last time my TopWindow property worked as expected with = being a comparator and not an assignment was in Real Studio 2012r2.1.
I took a project that uses this methodology that works properly under 12r2.1 and brought it forward to 19r1.1 and sure enough, calling:
If TopWindow = WWizard Then
Causes the WWizard window to be opened. It seems that the “If” is not being noticed and the = as Assignment is being used instead of = as comparison.
I went back to the Computed Property and yes - the
If TopWindow = WMain Then
IS calling the setter instead of the getter.
That seems VERY wrong.
I can duplicate this in a simple 2 window demo. Report created.
Happens on all three platforms.
[quote=438652:@Tim Jones]IS calling the setter instead of the getter.
That seems VERY wrong.[/quote]
I spewed my Coka-Cola onto my keyboard - thanks, Rick
Time to pull out a different keyboard!
WWizard.Open sets topwindow
There’s your bug - literally
WWizard.Open sets top window
Turn implicit instance OFF on WWizard & check if TopWindow IsA Wwizard
And it all works as expected
They both set TopWindow = Me. This needs to be since the user can change work environments during their use of the app.
But - why is the Setter called on a comparison??? That is still a bug.
Because WWizard has implicit instance on and, since it had not been opened before, an instance is created and so the open event runs
Not a bug
Turn implicit instance OFF on WWizard & check if TopWindow IsA Wwizard and the bug does not exist any more
This is a great illustration of the dangers osf Implicit Instance
You get funky hard to track down weird bugs like this that appear to make no sense
WWizard is a GLOBAL function that the IDE generated for you
so what you have when you write
If TopWindow = WWizard
- its a global property no need to “call anything” (well maybe the getter)
WWizard - this is a GLOBAL function that returns a wwizard window write for you by the IDEwhen implicit instance is ON
- call the function
- does the implcit instance already exist ? (basically its a static local to the method)
- nope its doesnt so create it
- creating it causes the constructor & open event to run
- the open event causes TopWindow to be changed (this is your code)
- now we have the instance return it
and voila by the time this has returned it LOOKS like the comparison has done an assignment but it really hasnt
Your code path by using implicit instance has done this
If in Wwizard you added the constructor and put a break in there and in the open event for Wwizard you literally could follow this whole code path just as I described
Its not a framework bug at any rate
I understand what you’re getting at. It just makes sharing code between multiple Windows that could be top level windows far more code intensive than previously functioning code required since in addition to testing in an If block, I also pass it to a number of dialogs’ .ShowWithin(TopWindow) and .ShowModalWithin(TopWindow) calls.
In light of this, even if I move to non-implicit windows, it seems that simply changing my logic to use Window(0) since the proper window will always be Window(0) when I need to check this. Thoughts?
if that scheme ever worked then there was a bug in that old code or the framework
possibly thats why it stopped working back then
execution should_always_ have done this at least the very first time
another way to avoid this is make sure that Wwizard exists at the outset - maybe its hidden
all you’d have to do is reference something about it or just create the instance
dim w as new Wwizard = Wwizard
in the app open event but make sure wwizard is, in the IDE, set to NOT be visible
then the implicit instance creation wont cause the sequence of events to go through the constructor & open right then as the window will already have been created
or, as I said, make it NOT implicit instance and make the comparison not = but IsA
implicit windows are basically singletons unless you actually call New to create a second
that said Window(0) should as far as I know always BE the top window
however, with the code path as it is, Window(0) would still appear to change because of the implicit instance so you’d have the same problem
moving to non-implcit would fix that
Okay - the shortest solution is to actually call all three possible windows (I forgot the actual job window) in the App.Open setting their .Visible to False. This takes care of getting the windows instantiated. Then, in the preferences check for which window to open, I set TopWindow to that window and then call TopWindow.Show.
Twice through the sequence appears to be the proof of success. Lots more testing tonight to be sure I didn’t overlook anything else.
Thanks for keeping your sledge hammer handy - I finally “got it”
No sledge hammer required
Its just one of those really hard things to follow with implicit instances
They’re handy sometimes but they have gotcha’s like this