You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PowerShell中清空并复用Windows Forms的DataGridView?

解决DataGridView重复加载数据时的红叉白屏问题

这个问题的核心原因有两个:一是后台线程直接操作UI控件违反了WinForms的线程安全规则,二是没有正确重置数据源并在主线程中更新UI。WinForms控件只能由创建它们的线程(也就是主线程)修改,后台线程直接赋值DataSource会导致控件状态混乱,第二次点击就触发了错误。

下面是修复后的完整代码,我会标注关键修改点:

Add-Type -AssemblyName System.Windows.Forms
$sync = [Hashtable]::Synchronized(@{})
$backgroundTask = {
    # 先通过Invoke让主线程清空DataGridView
    $sync.softwareTable.Invoke([Action]{
        $sync.softwareTable.DataSource = $null
        $sync.softwareTable.Rows.Clear()
    })

    $task1 = [PowerShell]::Create().AddScript({
        param($sync)
        # 执行数据查询(推荐用Get-CimInstance替代已弃用的Get-WmiObject)
        $softwareQuery = Get-CimInstance -ComputerName localhost -ClassName Win32_Product | Select-Object Name
        $softwareList = New-Object System.Collections.ArrayList
        $softwareList.AddRange($softwareQuery)

        # 必须通过Invoke回到主线程更新UI
        $sync.softwareTable.Invoke([Action]{
            $sync.softwareTable.DataSource = $softwareList
        })
    }).AddArgument($sync)

    $runspace = [RunspaceFactory]::CreateRunspace()
    $runspace.ApartmentState = "STA"
    $runspace.ThreadOptions = "ReuseThread"
    $runspace.Open()
    $runspace.SessionStateProxy.SetVariable("sync", $sync)
    $task1.Runspace = $runspace
    $asyncResult = $task1.BeginInvoke()

    # 清理资源,避免内存泄漏
    $task1.EndInvoke($asyncResult)
    $task1.Dispose()
    $runspace.Close()
    $runspace.Dispose()
}

$mainForm = New-Object system.Windows.Forms.Form
$mainForm.Size = New-Object System.Drawing.Size(900,600)
$okButton = New-Object System.Windows.Forms.Button
$okButton.Location = New-Object System.Drawing.Point(280,5)
$okButton.Size = New-Object System.Drawing.Size(75,20)
$okButton.Text = "OK"
$okButton.Add_Click($backgroundTask) ;
$mainForm.Controls.Add($okButton)

$softwareTable = New-Object System.Windows.Forms.DataGridView -Property @{
    Location=New-Object System.Drawing.Point(5,30)
    Size=New-Object System.Drawing.Size(840,360)
    ColumnHeadersVisible = $true
}
$mainForm.Controls.Add($softwareTable)
$sync.softwareTable = $softwareTable

$mainForm.ShowDialog()

关键修改说明:

  • 线程安全的UI更新:所有对DataGridView的操作(清空、赋值数据源)都通过Invoke方法委托给主线程执行,这是WinForms线程安全的核心要求,避免跨线程操作导致的控件状态崩溃。
  • 彻底清空数据源:每次点击按钮时,先在主线程中将DataSource设为null并清空行,确保之前的数据被完全重置,不会和新数据产生冲突。
  • 资源清理:添加了EndInvoke、Dispose方法来清理PowerShell实例和Runspace,避免重复点击后出现内存泄漏问题。
  • 替换弃用命令:把Get-WmiObject换成了官方推荐的Get-CimInstance,兼容性和性能更好。

这样修改后,你可以重复点击OK按钮,DataGridView会正确清空并重新加载数据,不会再出现红叉白屏的问题。

内容的提问来源于stack exchange,提问作者jemandanders

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:08:21