vb.net - 在 Visual Basic (VS 2012 V11) 中进行跨线程时正确更新文本框

标签 vb.net multithreading textbox backgroundworker

  • 这是我的简短问题:如何使用 BackGroundWorker(或 InvokeRequired 方法)进行线程安全调用以将文本附加到文本框?

  • 这是我的问题,包含更多细节和背景:我一直在开发一个程序,该程序将文件从一个位置复制到另一个位置以进行备份。我设置了一个选项,当使用 FileSysteWatcher 修改文件时,该选项将保存文件。这是代码:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load
    
        Dim directoryPath As String = Path.GetDirectoryName(TextBox1.Text)
        Dim varFileSystemWatcher As New FileSystemWatcher()
        varFileSystemWatcher.Path = directoryPath
    
        varFileSystemWatcher.NotifyFilter = (NotifyFilters.LastWrite)
        varFileSystemWatcher.Filter = Path.GetFileName(TextBox1.Text)
        AddHandler varFileSystemWatcher.Changed, AddressOf OnChanged
        varFileSystemWatcher.EnableRaisingEvents = True
    
    End Sub
    
    Private Sub OnChanged(source As Object, ByVal e As FileSystemEventArgs)
    
        My.Computer.FileSystem.CopyFile(e.FullPath, TextBox2.Text & "\" & e.Name, True)
        TextBox3.ApendText("[New Text]") ' This line causes an error
    End Sub
    

除了更新 textbox3 中的文本之外,代码工作正常。当指定的文件被修改时,我需要更新文本框。这很重要,以便用户可以知道程序正在运行并拥有程序操作的完整日志。

引起的错误是:

Cross-thread operation not valid: Control 'TextBox3' accessed from a thread other than the thread it was created on.

我假设“AddHandler varFileSystemWatcher.Changed, AddressOf OnChanged”创建一个新线程。另外,在“OnChange Sub”中更新“textbox3”(以我的方式)不是线程安全的方式。所以我做了一些研究,发现了这篇文章:

How to: Make Thread-Safe Calls to Windows Forms Controls

本文解释了可以使用 InvokeRequired 或 BackgroundWorker 进行线程安全调用。我想使用 BackgroundWorker 进行线程安全调用(如果 InvokeRequired 更有效,那么我将使用它),但是提供的示例的这部分让我感到困惑:

' Do I need these imports to use the BackgroundWorker or InvokeRequired?
Imports System
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms

Public Class Form1
   Inherits Form ' Do I need this for what I am trying to do?

   ' This delegate enables asynchronous calls for setting
   ' the text property on a TextBox control.
   Delegate Sub SetTextCallback([text] As String)

   ' This thread is used to demonstrate both thread-safe and
   ' unsafe ways to call a Windows Forms control.
   Private demoThread As Thread = Nothing

   ' This BackgroundWorker is used to demonstrate the 
   ' preferred way of performing asynchronous operations.
   Private WithEvents backgroundWorker1 As BackgroundWorker

   Private textBox1 As TextBox
   Private WithEvents setTextUnsafeBtn As Button
   Private WithEvents setTextSafeBtn As Button
   Private WithEvents setTextBackgroundWorkerBtn As Button

   ' What is this part of the code for and do I need it?
   Private components As System.ComponentModel.IContainer = Nothing

   ' Again, What is this part of the code for and do I need it?
   Public Sub New()
      InitializeComponent()
    End Sub

   ' And again, What is this part of the code for and do I need it?
   Protected Overrides Sub Dispose(disposing As Boolean)
      If disposing AndAlso (components IsNot Nothing) Then
         components.Dispose()
      End If
      MyBase.Dispose(disposing)
    End Sub

上面代码的许多部分让我感到困惑。它有什么作用?我需要这段代码的哪些部分才能使用BackgroundWorker? InvokeRequired 方法由哪些部分组成?再次,如何使用 BackGroundWorker(或 InvokeRequired 方法)进行线程安全调用以将文本附加到文本框?(如果能解释上面的代码就太好了,但我所讲的只是真正需要的是如何以线程安全的方式更新文本框文本的示例。)

最佳答案

更改:

Private Sub OnChanged(source As Object, ByVal e As FileSystemEventArgs)
    My.Computer.FileSystem.CopyFile(e.FullPath, TextBox2.Text & "\" & e.Name, True)
    TextBox3.ApendText("[New Text]") ' This line causes an error
End Sub

致:

Private Sub OnChanged(source As Object, ByVal e As FileSystemEventArgs)
    My.Computer.FileSystem.CopyFile(e.FullPath, TextBox2.Text & "\" & e.Name, True)
    AppendTextBox(TextBox3, "[New Text]")
End Sub

Private Delegate Sub AppendTextBoxDelegate(ByVal TB As TextBox, ByVal txt As String)

Private Sub AppendTextBox(ByVal TB As TextBox, ByVal txt As String)
    If TB.InvokeRequired Then
        TB.Invoke(New AppendTextBoxDelegate(AddressOf AppendTextBox), New Object() {TB, txt})
    Else
        TB.AppendText(txt)
    End If
End Sub

这是使用匿名委托(delegate)的更新、简化版本:

Private Sub OnChanged(source As Object, ByVal e As FileSystemEventArgs)
    Dim filename As String = System.IO.Path.Combine(TextBox2.Text, e.Name)
    Try
        My.Computer.FileSystem.CopyFile(e.FullPath, filename, True)

        TextBox3.Invoke(Sub()
                            TextBox3.AppendText("[New Text]")
                        End Sub)

    Catch ex As Exception
        Dim msg As String = "Source: " & e.FullPath & Environment.NewLine &
            "Destination: " & filename & Environment.NewLine & Environment.NewLine &
            "Exception: " & ex.ToString()
        MessageBox.Show(msg, "Error Copying File")
    End Try
End Sub

关于vb.net - 在 Visual Basic (VS 2012 V11) 中进行跨线程时正确更新文本框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16529092/

相关文章:

c# - 如何使用Android向PC发送消息并实时接收

c++ - std::mutex 锁定顺序

asp.net - 如何设置多行文本框的最大长度?

c# - Visual Studio 2008 : is there any way to turn on the Class Name/Method Name drop downs in C#?(就像 VB.Net 一样)

javascript - 如果我将 Div 设置为 runat ="server",则不显示 Jqwidgets 图表

c++ - OpenMP - 使用 parallel 在循环中调用函数,使用 Mat 对象

.net - 我可以在让用户等待之前更新 WPF 状态栏文本吗?

memory - 在内存中表示格式化文本的最佳方式? C++

javascript - 如何使特定的文本值以不同的文本响应

mysql - Linux 上的 Vb.Net MySQL 出现 Mono 错误