WinForm文本框自动更新动态变量问题求助
PowerShell WinForm文本框自动更新USB连接状态的解决方法
问题原因
你的WMI事件能正常更新全局变量$Global:ConnectionStatus,但文本框无法自动同步,核心问题有两个:
- WMI事件的
-Action脚本块运行在后台线程,WinForm不允许跨线程直接修改UI控件,后台线程的修改操作会被静默阻止。 - 你添加的
TextChanged事件逻辑错误:试图监听文本框变化去修改不存在的$displayLabel,但实际需求是USB状态变化时更新文本框。
修复方案
通过控件的Invoke()方法在主线程更新UI,同时调整WMI事件的Action逻辑,直接更新文本框内容。用Register-WmiEvent的-MessageData参数把文本框对象传递给Action脚本块,避免依赖全局变量。
修改后的完整代码
# 初始化全局状态变量 $Global:ConnectionStatus = 'Nicht verbunden' #region Windows Forms初始化 [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") # 创建主窗体 $Form = New-Object System.Windows.Forms.Form $Form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::FixedSingle $Form.Text = "Test" $Form.Size = New-Object System.Drawing.Size(946, 580) $Form.StartPosition = "CenterScreen" $Form.AutoScroll = $True $Form.AutoSize = $True $Form.AutoSizeMode = "GrowOnly" $Font = New-Object System.Drawing.Font("Microsoft Sans Serif", 12) $Form.Font = $Font $Icon = [system.drawing.icon]::ExtractAssociatedIcon($PSHOME + "\powershell.exe") $Form.Icon = $Icon # 创建文本框 $Textbox1Connection = New-Object 'System.Windows.Forms.TextBox' $Textbox1Connection.Font = [System.Drawing.Font]::new('Microsoft Sans Serif', '9.75') $Textbox1Connection.Location = New-Object System.Drawing.Size(36, 45) $Textbox1Connection.Size = New-Object System.Drawing.Size(180, 22) $Textbox1Connection.Text = $Global:ConnectionStatus $Textbox1Connection.TextAlign = 'Center' $Textbox1Connection.ReadOnly = $True $Form.Controls.Add($Textbox1Connection) #endregion #region 注册USB设备监听事件 # 设备连接事件 $query = "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType=2" Register-WmiEvent -Query $query -Action { $volumeName = (Get-WMIObject -Class Win32_LogicalDisk -Filter "DeviceID='$($Event.SourceEventArgs.NewEvent.DriveName)'").VolumeName $statusText = "Laufwerk $volumeName verbunden" # 通过Invoke在主线程更新UI $Event.MessageData.Invoke({ param($text) $this.Text = $text }, $statusText) $Global:ConnectionStatus = $statusText } -MessageData $Textbox1Connection | Out-Null # 设备断开事件 $query = "SELECT * FROM Win32_VolumeChangeEvent WHERE EventType=3" Register-WmiEvent -Query $query -Action { $statusText = 'Nicht verbunden' $Event.MessageData.Invoke({ param($text) $this.Text = $text }, $statusText) $Global:ConnectionStatus = $statusText } -MessageData $Textbox1Connection | Out-Null #endregion # 显示窗体 $Form.Add_Shown({$Form.Activate()}) [void]$Form.ShowDialog() # 清理事件订阅 Get-EventSubscriber | Unregister-Event
关键说明
Invoke()方法:WinForm控件的Invoke()方法会把修改UI的委托提交到创建控件的主线程执行,彻底解决跨线程操作UI的限制。-MessageData参数:通过这个参数将文本框对象直接传递给WMI事件的Action脚本块,不需要依赖全局变量引用控件,逻辑更清晰可靠。- 事件注册时机:必须在文本框创建完成后再注册WMI事件,确保
-MessageData能传递有效的控件对象。
内容的提问来源于stack exchange,提问作者Frank
相关产品推荐
相关产品推荐

