winforms 以编程方式更新和配置窗体和控件的最有效方法

cyvaqqii  于 2023-02-09  发布在  其他
关注(0)|答案(2)|浏览(153)

我正在寻找一种方法来防止用户表单控件在我以编程方式添加它们时逐个出现,并寻找增强应用程序性能和视觉吸引力的方法。
比方说,我有一个Panel_Top,我通过编程添加了组合框,但实际情况是它们在创建时一个接一个地出现,我正在寻找一种方法来暂停面板和/或用户表单的刷新,以使所有这些通过编程添加的组合框同时出现,并且比现在更快。
我试过suspendlayout,它对我没有任何作用,或者我做错了。

MyForm.PanelTop.SuspendLayout = true

我还尝试将Panel_Top设置为不可见,如下所示:

MyForm.Top_Panel.visible = false

哪一种看起来和表现更好,或者它可能是一种安慰剂。
解决这个问题的正确方法是什么?
PS:如果有问题的话,我确实将表单设置为doublebuffer = true

iecba09b

iecba09b1#

我倾向于创建一个加载模式,显示在表单的顶部,呈现需要创建/显示的控件,这可以选择有一个进度条,随着控件的创建/显示而增加。随着加载模式的运行,需要添加控件的容器从SuspendLayout开始,添加控件,然后以ResumeLayout结束。
这使得在添加/显示控件的同时,为用户提供了一个视觉指示器,表明在幕后正在发生一些事情。
下面是一个加载模态的典型示例:https://www.vbforums.com/showthread.php?869567-Modal-Wait-Dialogue-with-BackgroundWorker,下面是使用它的示例:

Private ReadOnly _controlsToAdd As New List(Of Control)()

Private Sub MyForm_Show(sender As Object, e As EventArgs) Handles MyBase.Shown
    Using waitModal = New BackgroundWorkerForm(AddressOf backgroundWorker_DoWork,
                                               AddressOf backgroundWorker_ProgressChanged,
                                               AddressOf backgroundWorker_RunWorkerCompleted)
        waitModal.ShowDialog()
    End Using
End Sub

Private Sub backgroundWorker_DoWork(sender As Object, e As DoWorkEventArgs)
    Dim worker = DirectCast(sender, BackgroundWorker)
    For index = 1 To 100
        _controlsToAdd.Add(New ComboBox() With {.Name = $"ComboBox{index}"})
        worker.ReportProgress(index)
        Threading.Thread.Sleep(100) ' Zzz to simulate a long running process
    Next
End Sub

Private Sub backgroundWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
    Dim percentageCompleted = e.ProgressPercentage / 100
    ' do something with the percentageCompleted value
End Sub

Private Sub backgroundWorker_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs)
    PanelTop.SuspendLayout()
    PanelTop.Controls.AddRange(_controlsToAdd.ToArray())
    PanelTop.ResumeLayout()
End Sub
wko9yo5t

wko9yo5t2#

SuspendLayout()是使用WinForms处理此问题的正确方法。

但首先,这是一个你调用的 * 函数,而不是你设置的标志。
其次,不要忘记在更改结束时调用ResumeLayout()
最后,你需要确保你只在你开始改变面板中的控件时调用它们一次,然后在最后再调用一次。如果你对每个控件都使用它们,你不会得到任何好处。
因此,模式可能看起来像这样:

Public Sub SomeMethod()
    PanelTop.SuspendLayout() ' Prevent the panel from updating until you've finished

    ' Make a bunch of changes
    PanelTop.Controls.Clear()
    For Each ...
        PanelTop.Controls.Add( ... )
    Next 

    PanelTop.ResumeLayout() ' Allow the panel to show all the changes in the same WM_PAINT event
End Sub

您还需要确保其中没有DoEvents()/Invalidate()之类的内容,这些内容可能会调用windows消息循环并导致窗体自身重绘。

相关问题