首页 > 解决方案 > 使用 BackgroundWorker 通过 FileSystemWatcher 更新主窗体 UI?

问题描述

我在尝试使用 BackgroundWorker 来更新我的主表单 UI 以响应 FileSystemWatcher 事件被触发时有点卡住了。

  1. FileSystemWatcher 检查添加到特定文件夹的图像,触发 OnCreated Handler
  2. OnCreated 处理程序调用 RunWorkerAsync(e.FullPath) 将文件名传递给后台工作者
  3. 后台工作者 RunWorkerAsync 获取文件路径,并将项目添加到 List(Of Product)
  4. List(Of Product) 被添加到主 UI 上的 ListBox 控件

我的第一个问题是在后台工作人员完成后更新主 UI 线程。我在后台工作人员中处理图像,因为从图像生成缩略图需要几秒钟,并且不想锁定 UI。

我遇到的第二个问题是在我的事件第二次触发之后,并且抛出异常表明后台工作人员很忙。

Private HoldingTank As New List(Of Product)

Private Sub LoadImages()
    Me.ToolStripStatusLabelUpdate.Text = "Images Loading - Please Wait...."
    CheckedListBoxView.Items.Clear()
    HoldingTank = Me.CreateImageList()
    For Each product As Product In HoldingTank
        Me.CheckedListBoxView.Items.Add(New ListViewDataItem With {.Image = product.Image, .ImageAlignment = ContentAlignment.MiddleCenter, .Tag = product})
    Next
    Me.ToolStripStatusLabelUpdate.Text = "Ready"
End Sub

Public Sub WatchFolders()
    watcher.Path = PathImport
    watcher.Filter = "*.tif"
    AddHandler watcher.Created, AddressOf OnCreated
    watcher.EnableRaisingEvents = True
End Sub

 Sub OnCreated(sender As Object, e As IO.FileSystemEventArgs)
    BackgroundWorker1.RunWorkerAsync(e.FullPath)
 End Sub

 Private Sub BackgroundWorker1_LoadImages(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
     HoldingTank.Add(New Product() With {.FileName = path.getFileName(e.argument), .FileExtension = path.GetExtension(e.argument), .FileFullPath = e.argument, .Image = GenerateThumbnail(e.argument)})
     '// Function GenerateThumbnail returns an Image object
End Sub
  1. 一旦 BackgroundWorker 将项目添加到列表中,我如何更新 CheckedListBoxView 控件而不会获得非法的跨线程调用?
  2. 如果在工作人员完成之前引发另一个文件事件,我如何检查工作人员是否忙?

标签: vb.netwinforms

解决方案


首先,确保您已设置SynchronizingObject. FileSystemwatcher如果您没有,它将在辅助线程上引发其事件,在这种情况下您不希望这样做。您应该将表单分配给该属性。

其次,您不要触摸DoWork事件处理程序中的 UI 或从中调用的任何方法。这都是在辅助线程上执行的,除了 UI 线程之外,您不能在任何地方修改 UI。您可以在DoWork事件处理程序中完成所有工作,然后将结果数据分配给e.Result属性。

然后处理在RunWorkerCompletedUI 线程上执行的事件,从属性中取回该数据e.Result,然后更新 UI。我不确切知道您在那里使用的是什么控件,但您应该能够在辅助线程上创建项目,但是您需要将它们添加到 UI 线程上的控件中。

你可以在这里BackgroundWorker找到我自己的例子。


推荐阅读