3

I have narrowed my problem to this simple case, but can't seem to find what's going on:

  • I have two forms, on with a single button, and the other empty.
  • On clicking the button, form1 hides and shows form2
  • when showung up, form2 will hide, and show form1 back again

In addition, when entering VisibleChanged, Form2 will stop with a MsgBox The code follows.

Now the Expected behavior, when clicking on button would be

  • Form1 hides
  • first MsgBox for visible turning true due to Form1 calling Form2.show
  • second MsgBox for visible turning false due to Form2 calling Me.hide
  • Form1 shows up

all this does happend, but then,

  • Form2 shows up (Form1 is still there)
  • a msgbox shows up (telling that form2.visible is True again)
  • a msgbox shows up (telling that form2.visible is False now)
  • Form2 hides

Any idea why?

here's the code:

Public Class Form1
    Private Sub ButtonGO_Click(sender As Object, e As EventArgs) Handles ButtonGO.Click
        Me.Hide()
        Form2.Show()
    End Sub
End Class

and also

Public Class Form2
    Dim calls As Integer = 0
    Private Sub Form2_VisibleChanged(sender As Object, e As EventArgs) Handles Me.VisibleChanged
        calls += 1
        MsgBox("calling : " & calls & " / Me.Visible : " & Me.Visible)
        If Me.Visible Then
            Me.Hide()
            Form1.Show()
        End If
    End Sub
End Class
GSerg
  • 76,472
  • 17
  • 159
  • 346
user3617487
  • 155
  • 11
  • Apparently calling `Me.Hide` from a `VisibleChanged` handler makes the event happen one more time after the original handler returns. That is, calling `Hide` causes an immediate nested `VisibleChanged` like it should, the second handler exits doing nothing, the control proceeds to `Form1.Show` and exits the original handler, and then `VisibleChanged` happens again. I'm not sure if it's a bug or something obscure but expected, but if you want it to stop I suggest you call `Me.Hide` from some other event, not `VisibleChanged`. – GSerg May 17 '17 at 09:12
  • 1
    The Visible property in Winforms is a really big deal and very unintuitive. Setting it to True (or calling Show, same thing) has a lot of side-effects, it is the trigger that Winforms uses to create the native window. One thing you cannot do is jerk the floor mat and set it back to False in any event that runs due to the window getting created or made visible. As you found out. It is not clear why you are asking this, but the only way to defeat Show() is by overriding SetVisibleCore() and setting the argument to False before calling MyBase.SetVisibleCore(). – Hans Passant May 17 '17 at 09:22
  • Hi hans. the point of this closing is that some checks are to be performed, and if they fail, the form will refuse to show up. I clearly see that this can be done before calling form2.show. However, my point here was to understand that strange behavior that I stumbled upon. Now I tried replacing 'Me.hide()' in form2, with 'Me.SetVisibleCore(False)', and I still get the same behavior. Did I get you wrong ? – user3617487 May 17 '17 at 09:36
  • @user3617487 Now that [we understand the issue better](https://meta.stackexchange.com/q/66377/147640) it would appear you want to stop using [VB6-style default-instance form references](http://stackoverflow.com/a/33765125/11683) to forms and create a constructor for `Form2` that will throw an exception if conditions are not met. – GSerg May 17 '17 at 09:42
  • Thanks GSerg, that should do, but unfortunately it's too advanded for me (I'm teaching VB to first year students.. so this goes far beyond their knowledge). if there's no simple way in 'plain and simple' VB style, I'll stick to removing check from the visiblechanged and put it beforehand in the caller (meaning form1 in this skeleton case) which indeed makes perfect sense – user3617487 May 17 '17 at 09:53
  • On second thought.. this might not be the solution in my toy world : Form1 and Form2 are not built by new in this case, they already exist and only change their visible status... the constructor would just not be called up, would it ? – user3617487 May 17 '17 at 09:57
  • They only come into existence because you are trying to access a form instance with the class name. If you don't try, they are not created. You can't really do this kind of thing, it's something VB.NET specifically has to pretend you can do, and only in relation to `Form`s. It's a legacy feature, and it should not be used, in my opinion. Even worse in my opinion is teaching that to students. Forms are no different to other classes, and if the students can grasp the concept of `= New MyClass()` they can understand `= New Form2()`. – GSerg May 17 '17 at 10:26
  • I have to say - I dont often see such well asked questions - Nicely done. And thanks to @GSerg for the formatting :) – David Wilson May 18 '17 at 08:05

1 Answers1

0

Ok, so in order to close : thanks for your answers, they tell what to do for a "full" VB coder.

As for my students, i.e. people who just use drag-n-drop-VB, the solution is to check conditions in Form1 and then only call Form2 when it will show up.

Note : This might seem trivial, but it may not be compliant with the "encapsulation" idea. That is what brought this issue up in the first place in my case.

user3617487
  • 155
  • 11