amber
amber

Reputation: 1137

When is Control.Visible = true turns out to be false?

I have a C# WinForms project that's very wizard like in its functionality. The individual steps live on a class called StepPanel, which inherits from the Panel control, within the form and those panels are organized in an array.

What I've run into is that when UpdateUI() is called and walks the array, adjusts the wizards step title text for the current step, it makes sure that all of the inactive steps are hidden, and ensures that the active step is visible, in the right spot, and is the right size.

Here's the code:

    private void UpdateUI()
    {
        // If the StepIndex equals the array length, that's our cue 
        // to exit.
        if (StepIndex == Steps.Length)
        {
            Application.Exit();
            return;
        }

        for (var xx = 0; xx < Steps.Length; xx++)
        {
            if (xx == StepIndex)
            {
                if (!String.IsNullOrEmpty(Steps[xx].Title))
                {
                    LabelStepTitle.ForeColor = SystemColors.ControlText;
                    LabelStepTitle.Text = Steps[xx].Title;
                }
                else
                {
                    LabelStepTitle.ForeColor = Color.Red;
                    LabelStepTitle.Text =
                        Resources.UiWarning_StepTitleNotSet;
                }
            }
            else
            {
                Steps[xx].Visible = false;
            }
        }

        Steps[StepIndex].Top = 50;
        Steps[StepIndex].Left = 168;
        Steps[StepIndex].Width = 414;
        Steps[StepIndex].Height = 281;
        Steps[StepIndex].Visible = true;

        SetNavigationButtonState(true);
    }

When everything is said and done, Steps[StepIndex].Visible == false.

I'm still perplexed by this behavior because I was working less than 30 minutes ago.

Upvotes: 10

Views: 19246

Answers (4)

schlebe
schlebe

Reputation: 3716

I encountered same issue using MDIForm in VB.net and Sani Singh Huttunen explanation is correct for me.

I post this answer to give more explanations and also a specific solution or a work around.

When I click on a specific menu to load a new MDI Child form, my program excute following code

Dim frm As New FrmPaiement
frm.MdiParent = Me
Call frm.NewRecord()
Call ReorganizeControlTopPositions(frm.DataPanel)
frm.Show()

where FrmPaiement is a Form class that originally contains a lot of controls and DataPanel is central panel that contains all data TextBox, CheckBox, ComboBox and DateBox controls.

enter image description here

But these time, some controls are hidden in frm.NewRecord() function.

enter image description here

ReorganizeControlTopPosition() function is called to reduce gaps between remainding visible controls

enter image description here

For information, VB.Net code of ReorganizeControlTopPositions() is following

Public Sub ReorganizeControlTopPositions(ctlContainer As Panel)
    'Put all controls in a List(Of Control) and sort it on Top position
    For Each ctl As Control In ctlContainer.Controls
        lstControls.Add(ctl)
    Next

    lstControls.Sort(Function(x, y) x.Top.CompareTo(y.Top))

    'Reduce gaps between 2 visibles controls

    Dim iLastTop As Integer = -1
    Dim nInvisible = 0
    Dim iLastControlTop As Integer = 0

    For Each ctl In lstControls
        If nInvisible > 0 Then
            If ctl.Visible Then
                If ctl.Top = iLastControlTop Then
                    ctl.Top = iLastTop
                Else
                    iLastControlTop = ctl.Top
                    ctl.Top = iLastTop + 32
                End If
            End If
        End If

        If ctl.Visible Then
            iLastTop = ctl.Top
        Else
            nInvisible += 1
        End If
    Next

End Sub

EXPLANATION OF ERROR

Since ReorganizeControlTopPositions() function is called before frm.Show() function, MDI Child is hidden and in debug mode, ctl.Visible contains always False !

If initialisation code if changed so that ReorganizeControlTopPositions() is called after frm.Show() call, program runs correctly and ctl.Visible contains "correct" value.

Dim frm As New FrmPaiement
frm.MdiParent = Me
Call frm.NewRecord()
frm.Show()
Call ReorganizeControlTopPositions(frm.DataPanel)

The only problem is that MDI Form is shortly (very quicly) displaying controls with gaps and a micro secund later without gaps.

The problem is linked to Microsoft implementation of Visible property.

Setting Visible property seems to change visible value of control but getting Visible value return only True if Visible property of control is True and also all containers containing this control are visibles !

What is written on Control.Visible property on learn.microsoft.com is extremly confuse !!!

Return True if the control and all its child controls are displayed; otherwise, false. The default is true.

The correct definition sould be

Return True if the control and all its PARENT controls are displayed; otherwise, false. The default is true.

Upvotes: 0

Ethan Cabiac
Ethan Cabiac

Reputation: 4993

There are several possibilities. When you attach a debugger on the line:

SetNavigationButtonState(true);

does Steps[StepIndex].Visible == true? If so, then make sure that StepIndex is actually the index you expected (not off by 1, and not reflecting the "previous" step). If you verify that the correct step is set to true, then you must be updating it somewhere else.

if Steps[StepIndex].Visible == false right after you set it to true, then either the getter on the Visible property is returning based on some calculation or an event was triggered that is changing it back to false.

HTH.

Upvotes: 0

Bit
Bit

Reputation: 1078

if (xx == StepIndex)

Is only going to be true and the end of the loop unless I am missing something.

Upvotes: 0

Sani Huttunen
Sani Huttunen

Reputation: 24375

If you set a parent/container control to Visible = false then setting any child controls to Visible = true will have no effect what so ever. The Visible property of the child control will still be false.

I don't know if it's what happens in this case since I don't know the structure of the controls but it seems to be a likely scenario.

To solve this you need to first set the parent/contianer control to Visible = true and THEN the child control(s).

Upvotes: 23

Related Questions