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

如何在PowerShell WinForm表格Overview列实现多进程带百分比进度条

PowerShell WinForm DataGridView 多行进度条实现方案

要实现每行独立的带百分比进度条,核心是自定义DataGridViewProgressColumn列类型,配合后台线程处理任务并安全更新UI,避免阻塞界面。以下是完整可运行的代码:

1. 定义自定义进度列

创建继承自DataGridViewImageColumn的自定义列,用于绘制带百分比的进度条:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

# 自定义进度列:绘制进度条+百分比文本
class DataGridViewProgressColumn : System.Windows.Forms.DataGridViewImageColumn {
    DataGridViewProgressColumn() {
        this.CellTemplate = [DataGridViewProgressCell]::new()
        this.Width = 150
    }
}

class DataGridViewProgressCell : System.Windows.Forms.DataGridViewImageCell {
    hidden [int]$progressValue = 0

    DataGridViewProgressCell() {
        this.ValueType = [int]
    }

    # 重写绘制方法,绘制进度条和百分比
    hidden [void] Paint([System.Drawing.Graphics]$g, [System.Drawing.Rectangle]$clipBounds, [System.Drawing.Rectangle]$cellBounds, [int]$rowIndex, [System.Windows.Forms.DataGridViewElementStates]$cellState, [object]$value, [object]$formattedValue, [string]$errorText, [System.Windows.Forms.DataGridViewCellStyle]$cellStyle, [System.Windows.Forms.DataGridViewAdvancedBorderStyle]$advancedBorderStyle, [System.Windows.Forms.DataGridViewPaintParts]$paintParts) {
        if ($value -is [int]) {
            $this.progressValue = $value
        }

        # 绘制单元格背景
        $g.FillRectangle([System.Drawing.SolidBrush]$cellStyle.BackColor, $cellBounds)
        
        # 绘制进度条背景
        $progressBarBounds = [System.Drawing.Rectangle]::new($cellBounds.X + 2, $cellBounds.Y + 2, $cellBounds.Width - 4, $cellBounds.Height - 4)
        $g.DrawRectangle([System.Drawing.Pens]::Gray, $progressBarBounds)
        
        # 绘制进度条填充
        if ($this.progressValue -gt 0) {
            $fillWidth = [int]($progressBarBounds.Width * ($this.progressValue / 100.0))
            $g.FillRectangle([System.Drawing.SolidBrush][System.Drawing.Color]::LightGreen, $progressBarBounds.X, $progressBarBounds.Y, $fillWidth, $progressBarBounds.Height)
        }
        
        # 绘制百分比文本
        $text = "$($this.progressValue)%"
        $textSize = $g.MeasureString($text, $cellStyle.Font)
        $textX = $cellBounds.X + ($cellBounds.Width - $textSize.Width) / 2
        $textY = $cellBounds.Y + ($cellBounds.Height - $textSize.Height) / 2
        $g.DrawString($text, $cellStyle.Font, [System.Drawing.Brushes]::Black, $textX, $textY)
    }
}

2. 初始化GUI并启动后台任务

创建Form和DataGridView,添加自定义列,用后台线程执行任务并更新对应行的进度:

# 创建主窗体
$form = [System.Windows.Forms.Form]::new()
$form.Text = "多任务进度监控"
$form.Size = [System.Drawing.Size]::new(600, 400)

# 创建DataGridView
$dgv = [System.Windows.Forms.DataGridView]::new()
$dgv.Dock = [System.Windows.Forms.DockStyle]::Fill
$dgv.AutoGenerateColumns = $false

# 添加列
$dgv.Columns.Add(([System.Windows.Forms.DataGridViewTextBoxColumn]::new() {
    Name = "TaskName"
    HeaderText = "任务名称"
    Width = 200
}))
$dgv.Columns.Add(([DataGridViewProgressColumn]::new() {
    Name = "Overview"
    HeaderText = "进度"
}))

# 添加任务行
$tasks = @(
    @{ Name = "文件备份"; Progress = 0 },
    @{ Name = "数据库同步"; Progress = 0 },
    @{ Name = "日志清理"; Progress = 0 }
)
foreach ($task in $tasks) {
    $rowIndex = $dgv.Rows.Add($task.Name, 0)
    $dgv.Rows[$rowIndex].Tag = $task # 存储任务对象用于后续更新
}

$form.Controls.Add($dgv)

# 启动后台线程处理任务,避免阻塞UI
$backgroundWorker = [System.ComponentModel.BackgroundWorker]::new()
$backgroundWorker.WorkerReportsProgress = $true
$backgroundWorker.DoWork += {
    param($sender, $e)
    # 模拟三个任务依次执行
    foreach ($row in $dgv.Rows) {
        $task = $row.Tag
        for ($i = 0; $i -le 100; $i += 10) {
            Start-Sleep -Milliseconds 200 # 模拟任务耗时
            # 报告进度:行索引 + 当前进度值
            $sender.ReportProgress($row.Index, $i)
        }
    }
}

# 处理进度更新事件,跨线程更新UI
$backgroundWorker.ProgressChanged += {
    param($sender, $e)
    $rowIndex = $e.ProgressPercentage
    $progressValue = $e.UserState
    # 用Invoke确保在UI线程更新控件
    $dgv.Invoke({
        $dgv.Rows[$rowIndex].Cells["Overview"].Value = $progressValue
        $dgv.Refresh() # 刷新单元格触发重绘
    })
}

# 任务完成后提示
$backgroundWorker.RunWorkerCompleted += {
    [System.Windows.Forms.MessageBox]::Show("所有任务完成!")
}

# 窗体加载时启动后台任务
$form.Load += {
    $backgroundWorker.RunWorkerAsync()
}

# 显示窗体
$form.ShowDialog() | Out-Null

关键说明

  • 自定义列重绘:通过重写Paint方法,手动绘制进度条和百分比文本,实现带文字的进度显示。
  • 后台线程:使用BackgroundWorker执行耗时任务,避免UI线程阻塞,保证窗体启动后立即响应。
  • 跨线程UI更新:WinForm控件只能在创建它的线程操作,所以用Invoke方法将更新操作切换到UI线程执行。
  • 行关联任务:通过Row.Tag存储任务对象,方便后台线程找到对应行更新进度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 19:25:55