何时 Control.Visible = true 变为 false?

9
我有一个C# WinForms项目,它的功能非常类似于向导。各个步骤都存储在一个名为StepPanel的类中,该类继承自Panel控件,并位于窗体中,这些面板以数组的形式组织。
我遇到的问题是,当调用UpdateUI()并遍历该数组时,会调整向导当前步骤的标题文本,确保所有非活动步骤都被隐藏,并确保活动步骤可见,处于正确的位置和正确的大小。
以下是代码:
    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);
    }

当一切结束时,Steps[StepIndex].Visible == false。

我仍然感到困惑,因为不到30分钟之前我还在工作。


你在过去的30分钟内有更改过任何东西吗? - Beth
是的,它目前正在积极开发中。 - amber
方法 SetNavigationButtonState 是用来做什么的? - Paulo Santos
表单底部有三个按钮:返回/重新开始、下一步/完成和取消。该方法整合了维护它们状态(即启用/禁用、当前按钮文本)的逻辑,基于您所处的流程步骤。 - amber
也许你最近所做的任何更改都导致了这个问题。 - Beth
4个回答

21
如果你将父/容器控件设置为Visible = false,那么将任何子控件设置为Visible = true都不会产生任何效果。子控件的Visible属性仍将为false
我不知道在这种情况下会发生什么,因为我不知道控件的结构,但这似乎是一个可能的情况。
要解决这个问题,你需要首先将父/容器控件设置为Visible = true,然后再设置子控件的可见性。

似乎 StepPanel 成为了另一个被隐藏的 StepPanel 的子元素。 - amber
5
很好,你解决了它。我的最后一条评论实际上是不正确的。您可以在父级控件之前将子级控件的可见属性设置为true。该属性将保持为false,但是当您将父级属性设置为true时,.Net将“神奇地”记住子级控件的状态并相应地设置它们。 - Sani Huttunen
我认为这一切都发生了,因为我试图将StepPanels排成一列,一个在另一个上面,而设计师试图提供帮助。我已经添加了代码,如果StepPanel的父级不是表单,则将其删除,然后将其添加到表单的控件集合中。 - amber

0

有几种可能性。当您在该行附加调试器时:

SetNavigationButtonState(true);

判断Steps[StepIndex].Visible == true吗?如果是这样,请确保StepIndex实际上是您预期的索引(不是偏移1,也不反映“上一个”步骤)。如果您验证了正确的步骤设置为true,则必须在其他地方更新它。

如果您将其设置为true后立即出现Steps[StepIndex].Visible == false,则可能是可见属性的getter基于某些计算返回或触发了更改它回false的事件。

希望对您有所帮助。


0

if (xx == StepIndex)

只有在循环结束时才会为真,除非我漏掉了什么。


由于我们不知道StepIndex在哪里被设置,因此您不能做出这种假设。 - Sani Huttunen
StepIndex 跟踪用户所在的步骤,这与数组中的 StepPanel 相对应。 - amber
@Sani Huttunen,你是正确的,我在顶部的代码中读错了。 - Bit

0

我在使用VB.net中的MDIForm时遇到了同样的问题,Sani Singh Huttunen的解释对我来说是正确的。

我发布这个答案是为了提供更多的解释,以及一个具体的解决方案或解决方法。

当我点击特定菜单以加载新的MDI子窗体时,我的程序执行以下代码:

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

这里,FrmPaiement 是一个包含大量控件的表单类,而 DataPanel 是中央面板,包含所有数据文本框、复选框、组合框和日期框控件。

enter image description here

但是这次,一些控件被隐藏在frm.NewRecord()函数中。

enter image description here

ReorganizeControlTopPosition() 函数被调用以减少剩余可见控件之间的间隙。

enter image description here

有关信息,ReorganizeControlTopPositions() 的 VB.Net 代码如下:

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

错误解释

由于ReorganizeControlTopPositions()函数在frm.Show()函数之前被调用,MDI子窗口处于隐藏状态且处于调试模式,ctl.Visible始终为False

如果将初始化代码更改为在frm.Show()调用之后调用ReorganizeControlTopPositions(),程序将正常运行且ctl.Visible包含“正确”的值。

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

唯一的问题是 MDI 表单会很快地显示带有间隙的控件,而在微秒后又不带间隙。
这个问题与 Microsoft 的 Visible 属性实现有关。
设置 Visible 属性似乎会改变控件的可见值,但获取 Visible 值只返回 True,如果控件的 Visible 属性为 True,并且包含此控件的所有容器都是可见的!
learn.microsoft.com 上写的 Control.Visible 属性非常混乱!!!
如果控件及其所有子控件都显示,则返回 True;否则返回 false。默认值为 true。
正确的定义应该是
如果控件及其所有父控件都显示,则返回 True;否则返回 false。默认值为 true。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接