Hi, I am new to the multithreading concept, and I'm not sure if I completely understand it yet but regardless, I need to find out why this error is happening. I'm using VS 2010 Professional Beta 1 & .NET Framework 4.0 (have also tried this in VB Express 2008). I have a few questions that I would like answered. What I am trying to do is run a background thread to search through a string array of file names. In the process I need to make sure that my background thread has access to the UI thread so that it can update the controls and have the UI remain responsive. I think that I have this part down (will show code soon), but I think that I am not completely understanding how to use Lambada expressions, so here's my code:
If Not pbResults.Dispatcher.Thread Is searchThread Then
pbResults.Dispatcher.BeginInvoke(Sub() pbResults.Value = (i / UBound(strFiles)) * 100, New Object() {Nothing})
End If
pbResults.Value = (i / UBound(strFiles)) * 100
This is the code that throws the ParameterMismatchException. I am unsure of two things, the syntax and usage of the Lambada expression and also if I am checking for the background thread's access to the UI thread correctly. Thanks in advance for any help. |
| Snake22 |
Unless you are using something very, very, very specific, use System.ComponentModel.BackgroundWorker class. I implements events on the UI thread side and takes care of all the troubles you're finding. Bigsby, Lisboa, Portugal -
O que for, quando for, é que será o que é...
http://bigsby.eu |
| Bigsby |
Thanks for your help, I'll give it a shot. |
| Snake22 |
Ok, I tried the background worker with no results. I am getting the error the the BeginInvoke method is supposed to avoid, which is the background thread (worker)does not have access to the UI thread. Here is where I get the error:
Private Sub searchThread_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles searchThread.DoWork
If txtSearchString.Text <> "" Then
Search(txtSearchString.Text)
End If
End Sub
I'm not really sure what I am supposed to do... do I still have to invoke the progressbar or the window etc... ? Thanks again. |
| Snake22 |
That's when you use BackgroundWorker.ReportProgress method that raises the ProgressChanged event that lives on the UI thread. Bigsby, Lisboa, Portugal -
O que for, quando for, é que será o que é...
http://bigsby.eu |
| Bigsby |
Ok, I got the worker running correctly with no errors (it didn't take me 2 hours... I had class, so sorry for not responding in a while). But the next problem is that the UI is still unresponsive during the search routine. Is there a certain way that I should be implementing the search routine so that the UI remains responsive? Here's the routine I made for the purposes of this small application:
Private Sub Search(ByVal strMatch As String)
Dim strSearchArray() As String
Dim iCurrent As Integer = 0
Dim strSearchWords() As String = strMatch.Split(" ")
strResults = Nothing
If strMatch <> "" Then
Dim iFileBound As Integer = UBound(strFiles)
Dim iCurrentLoop As Integer = 0
For i As Integer = 0 To iFileBound
iCurrentLoop = i
strSearchArray = strFiles(i).Split("\")
For x As Integer = 0 To UBound(strSearchArray)
If LCase(strSearchArray(x)) = LCase(strMatch) Then
ReDim Preserve strResults(iCurrent)
strResults(iCurrent) = strFiles(i)
iCurrent += 1
End If
If strSearchWords.Count > 1 Then
For intCount As Integer = 0 To UBound(strSearchWords)
If LCase(strSearchWords(intCount)) = LCase(strMatch) Then
ReDim Preserve strResults(iCurrent)
strResults(iCurrent) = strFiles(i)
iCurrent += 1
End If
Next
End If
Next
If InStr(1, LCase(strFiles(i)), LCase(strMatch)) > 0 Then
ReDim Preserve strResults(iCurrent)
strResults(iCurrent) = strFiles(i)
iCurrent += 1
End If
searchThread.ReportProgress((i / iFileBound) * 100)
Next
End If
End Sub
It makes sense why it is not updating the UI in real time, because the routine is pretty much a few loops. I was under the impression that the background worker would negate that though... am I wrong? Thanks again. |
| Snake22 |
What matters isn't really the method you're running with the BackgroundWorker but the way you're setting the BackgroundWorker. If it's set correctly there should be no UI interference unless you have tons of ReportProgress calls. Can you provide your BackgroundWorker setting and calling? Bigsby, Lisboa, Portugal -
O que for, quando for, é que será o que é...
http://bigsby.eu |
| Bigsby |
I have the background worker named searchThread declared as a withevents variable:
Private WithEvents searchThread As System.ComponentModel.BackgroundWorker
This is where I initialize an instance of the BackgroundWorker class (when the search button is pressed):
Private Sub btnSearch_Click(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles btnSearch.Click
If strDirectory <> "" Then
If Not strFiles Is Nothing Then
If strFiles.Length > 0 Then
If txtSearchString.Text <> "" Then
lstResults.Items.Clear()
Try
searchThread = New System.ComponentModel.BackgroundWorker
searchThread.WorkerReportsProgress = True
searchThread.RunWorkerAsync(txtSearchString.Text)
Catch ex As Exception
MsgBox(ex.Message)
Exit Sub
End Try
End If
End If
End If
End If
End Sub
Those are the only instances in the code that I reference the worker other than to report the progress in the search routine. Thanks again. |
| Snake22 |
You must have DoWork and ProgressChanged handlers some where. How many times is ReportProgress call and with what interval? What happens on ProgressChanged handler?
Bigsby, Lisboa, Portugal -
O que for, quando for, é que será o que é...
http://bigsby.eu |
| Bigsby |
Oh, sorry about that:
Private Sub searchThread_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles searchThread.DoWork
Search(e.Argument)
End Sub
Private Sub searchThread_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles searchThread.ProgressChanged
pbResults.Value = e.ProgressPercentage
If e.ProgressPercentage >= 100 Then
If Not strResults Is Nothing Then
For Each sResult As String In strResults
If Not sResult Is Nothing Then
lstResults.Items.Add(sResult)
End If
Next
End If
End If
End Sub
|
| Snake22 |
The only time I call ReportProgress is in the search routine after it is done analyzing each file. |
| Snake22 |
What is the typical value for iFileBound when you run the search? Remember it's only necessary to call ReportProgress when you actually have something to change in the UI, so there's no point in calling it ifthe progress has only changed by 0.001%. As the other poster stated, you could be calling it too often. |
| dekurver |
iFileBound could be anywhere from 0 to infinity really, it depends on the directory that is selected. That seems to be irrelavent though because I've tested it in a directory with around 200 files and another with 50 or so files, and still the UI does not update. |
| Snake22 |
That's a complete different matter. If you set a breakpoint here:
lstResults.Items.Add(sResult)
is it hit?
Bigsby, Lisboa, Portugal -
O que for, quando for, é que será o que é...
http://bigsby.eu |
| Bigsby |
If you stick a "When Hit" breakpoint (right-click on the breakpoint and select "When Hit") on the line that updates the progress barand print out the ProgressPercentage value, do you seethe percentage valuesthat you would expect to see? |
| dekurver |
The lstResults breakpoint does hit, and when I do a "when hit" breakpoint I do see the values that I expect to see. I'm also noticing that my search routine returns several duplicate entires, and I've already tried doing:
If strResults.Contains(strFiles(i)) = False Then
' resize array and set new value
End If
That method returns duplicate results, and I'm not sure why... |
| Snake22 |
I've found a new symptom... and it points towards something in the search routine. When the search term is greater than 1 character in length, the UI is not updated. However, when the search term is only one character it does update the UI... I'm not really sure what this means but I will figure it out sooner or later.
Update: After further debugging, I've found that if the search term contains more than one word, it will also update the UI. |
| Snake22 |