3
votes

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
1
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
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
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
@user3617487 Now that we understand the issue better it would appear you want to stop using VB6-style default-instance form references to forms and create a constructor for Form2 that will throw an exception if conditions are not met. - GSerg
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

1 Answers

0
votes

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.