Update Text Box Properly when Cross-threading in Visual Basic (VS 2012 V11)

匿名 (未验证) 提交于 2019-12-03 01:08:02

问题:

  • Here is my question in short: How do I use the BackGroundWorker (or InvokeRequired method) to make thread-safe calls to append text to a text box?

  • Here is my question in with much detail and background: I've been working on a program that copies file from one location to another for backup purposes. I set an option that will save a file when the file is modified using the FileSysteWatcher. Here is the code:

    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 

The code works fine except for updating the text in textbox3. I need the textbox to update when the file specified is modified. This is important so that the user can know the program is working and to have a complete log of the programs operations.

The error that is caused is:

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

I'm assuming "AddHandler varFileSystemWatcher.Changed, AddressOf OnChanged" creates a new thread. Also, updating "textbox3" within the "OnChange Sub" (in the way I did) is not a thread-safe manner. So I did some research and found this article:

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

The article explains that one can use InvokeRequired or a BackgroundWorker to make thread-safe calls. I would like to use the BackgroundWorker to make a thread-safe call (if InvokeRequired is more efficient then I'll use that), but this portion, of the example provied, leaves me confused:

' 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 

Many parts of the above code leave me confused. What does it do? What parts of this code do I need to use the BackgroundWorker? What parts for the InvokeRequired method? Again, How do I use the BackGroundWorker (or InvokeRequired method) to make thread-safe calls to append text to a text box? (It'd be great to have the code above explained, but all I really need is one example of how to update the text of a text box in a thread-safe manner.)

回答1:

Change:

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 

To:

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 


回答2:

You can also use SynchronizationContext. Be careful to get a reference to it from the constructor. There's a great article on this at CodeProject.com: http://www.codeproject.com/Articles/14265/The-NET-Framework-s-New-SynchronizationContext-Cla

Imports System.IO Imports System.Threading  Public Class Form1     Private m_SyncContext As System.Threading.SynchronizationContext     Private m_DestinationPath As String      Public Sub New()          ' This call is required by the designer.         InitializeComponent()          ' Add any initialization after the InitializeComponent() call.         Me.m_SyncContext = System.Threading.SynchronizationContext.Current     End Sub      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load         Me.m_DestinationPath = Me.TextBox2.Text         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, Me.m_DestinationPath & "\" & e.Name, True)         Me.m_SyncContext.Post(AddressOf UpdateTextBox, "[New Text]")     End Sub      Private Sub UpdateTextBox(param As Object)         If (TypeOf (param) Is String) Then             Me.TextBox3.AppendText(CStr(param))         End If     End Sub End Class 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!