Cross thread operation not valid - vb.net

im trying to access a rich textbox on another form im using the following code to do so:
Private Delegate Sub StringDelegateChat(text As String, window As ChatWindow)
Private Sub AppendTextChatWindows(text As String, window As ChatWindow)
Try
If window.RichTextBox1.InvokeRequired Then
window.Invoke(New StringDelegateChat(AddressOf AppendTextChatWindows), text, window)
Else
window.RichTextBox1.AppendText(text)
window.RichTextBox1.SelectionStart = window.RichTextBox1.Text.Length
window.RichTextBox1.ScrollToCaret()
End If
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
but i get the cross thread operation not valid error, i think it does this because it misses out the window.invoke part of the if statement. i also tried replacing theIf window.RichTextBox1.InvokeRequired Then to If InvokeRequired Then but it gets caught in a continues loop and a stack overflow error is thrown.
Thanks
Houlahan

I believe, on line 5, window.Invoke should be changed to window.RichTextBox1.Invoke.
Private Delegate Sub StringDelegateChat(text As String, window As ChatWindow)
Private Sub AppendTextChatWindows(text As String, window As ChatWindow)
Try
If window.RichTextBox1.InvokeRequired Then
window.RichTextBox1.Invoke(New StringDelegateChat(AddressOf AppendTextChatWindows), text, window)
Else
window.RichTextBox1.AppendText(text)
window.RichTextBox1.SelectionStart = window.RichTextBox1.Text.Length
window.RichTextBox1.ScrollToCaret()
End If
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub

Have you tried:
Private Sub AppendTextChatWindows(text As String, window As ChatWindow)
Try
If window.RichTextBox1.InvokeRequired Then
window.RichTextBox1.BeginInvoke(New StringDelegateChat(AddressOf AppendTextChatWindows), text, window)
Exit Sub
Else
window.RichTextBox1.AppendText(text)
window.RichTextBox1.SelectionStart = window.RichTextBox1.Text.Length
window.RichTextBox1.ScrollToCaret()
End If
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
End Sub
Basically, I am asking about BeginInvoke rather than Invoke. Although I would expect, as another poster mentioned, that you should be using the same thing you check the required against to invoke. (ie both window.invokeRequired & window.BeginInvoke or the control)

I cant see any errors in your code. You might want to check for any events that are fired when updating the RichTextbox. They might be causing a cross threading.
As a workaround to your problem, working with objects, you are less likely o encounter cross threading problems.

Related

Cast an Exception into a NonGenericException according to a Type variable

I would like to throw a System.Exception of a given Type, such Type being passed as an argument of the Sub which Throws the Exception.
Then I would call the Sub like this: Call ThrowEvent("Wrong format: MyString must comply with the following pattern ***, System.FormatException)
So far I came up with this, but DirectCast is not happy:
ExceptionType is not defined
Public Shared Sub ThrowEvent(ByVal Message As String, ByVal ExceptionType As Type)
Dim MyException As New System.Exception(Message)
MyException = DirectCast(MyException, ExceptionType)
Throw MyException
End Sub
I have never used DirectCast for anything othger than Interfaces (usually when playing around with Collections)
I found this but did not really understand the full picture..
I found this, but I do not understand how I am supposed to us the (Of T)
As comments already discussed, this is not good idea at all. The concept is generally wrong and the exceptin will mess your code anyway. You should do some Try/Catch with general handling instead.
But if you really want to wrap your "throw" to "log and throw", than the easiest was is this:
Public Shared Sub ProcessThrow(Ex As Exception)
'Do your logging here
Throw Ex
End Sub
and call it like
ProcessThrow(New FormatException("Wrong format: MyString must comply with the following pattern ***""))
Better way of doing this is
Public Shared Sub HandleEx(Ex As Exception)
'Do your logging here
End Sub
and call it like this
Try
'Do something
Throw New FormatException("Wrong format: MyString must comply with the following pattern ***")
Catch ex As Exception
HandleEx(ex)
'Recover
End Try
I understand this is not recommended and I will not implement this solution, however for completeness and to help understand how Generic functions work, here are two solutions:
.Message not needed
Public Shared Sub ThrowEvent(Of TException As {System.Exception, New})()
Throw New TException() 'Passing arguments to the creator is not permited
End Sub
.Message needed
Public Shared Sub ThrowEvent(Of TException As {System.Exception})(ByVal MyMessage As String)
Dim MyException As TException = Activator.CreateInstance(GetType(TException), New Object() {MyMessage})
Throw MyException
End Sub
Again, this answers the question, but the question seeks a strategy which is not recommended.

Update a label from a task

I'm trying to implement tasks in my program. I launch a task that will produce a log file, and after, I want to update the label to say "Log sucessfully saved".
Here is my code
Private Function Createlog(ByVal mylist As List(Of classTest))
Dim sw As New StreamWriter("log_list.log")
For index = 1 To mylist.Count - 1
sw.WriteLine(mylist(index).comments)
Next
sw.Close()
Try
Me.Invoke(UpdateLabel("Log sucessfully saved"))
Catch ex As Exception
End Try
Return 1
End Function
Private Function UpdateLabel(ByVal text As String)
Label1.Text = text
Return 1
End Function
I launch the task from the Main form in the Load() :
Dim tasktest = Task(Of Integer).Factory.StartNew(Function() Createlog(theList))
(I don't know if it is better to use the factory or declare as a task and then task.Start())
I have the error on the label update :
Cross-thread operation not valid: Control 'Label1' accessed from a thread
other than the thread it was created on.
Could you please explain why it doesn't work with the invoke method ? And do you have an alternative solution ?
Thanks for your help
First, UpdateLabel should be a Sub, not a Function. Second, this line is wrong:
Me.Invoke(UpdateLabel("Log sucessfully saved"))
Read it again. You are, in order, executing the UpdateLabel function, then passing the result of that function to Me.Invoke (if you used Sub instead of Function, the compiler should have warned you about the error).
This doesn't raise any compiler errors because a Function declared without As [Type] is defaulted to As Object, that can be cast to anything. It should be:
Me.Invoke(Sub()
UpdateLabel("Log sucessfully saved")
End Sub)
To simplify, your code can be rewritten like this:
Private Sub Createlog(ByVal mylist As List(Of classTest))
Dim sw As New StreamWriter("log_list.log")
For index = 1 To mylist.Count - 1
sw.WriteLine(mylist(index).comments)
Next
sw.Close()
Me.Invoke(Sub()
Label1.Text = "Log sucessfully saved"
End Sub)
End Sub

Can't delete file. File in use by another process

I have a program (simple file updater) which downloads a file. Before that, an old version of this file is queued for deletion. But if I edit this file e.g. in text editor (save and close it), then my program refuses to delete it.
I have sub like this
Private Sub delete_file(ByVal dir As String)
Try
If My.Computer.FileSystem.FileExists(dir) Then My.Computer.FileSystem.DeleteFile(dir)
Catch ex As Exception
Debug.WriteLine(ex.ToString())
Sleep(1000)
delete_file(dir)
End Try
End Sub
It never goes out of the recursion. Exception says that file is being used by other process, and waiting doesn't change anything.
Any clues?
[EDIT]
Changed Sub a bit, so it doesn't contain recursion in Exception handler
Private Sub delete_file(ByVal dir As String)
Dim ok As Boolean = True
Try
If My.Computer.FileSystem.FileExists(dir) Then My.Computer.FileSystem.DeleteFile(dir)
Catch ex As Exception
Debug.WriteLine(ex.ToString())
ok = False
End Try
If ok = False Then
Sleep(1000)
delete_file(dir)
End If
End Sub
Words "another process" are VERY ambiguous.
It turned out that other function from my program was opening the same file twice, and closing it only once. Fixing that removed problem with deleting it.
So when u're having the same error, try searching your program for other places when this file may be modified.
Thanks for comments, they surely gave me some hints about good programming.

Double exception throwing in a try / finally block

Here's the code example :
Try
Throw New FirstException()
Finally
Throw New SecondException()
End Try
I figured out it only throws SecondException out and FirstException just vanishes.
I thought FirstException would be inside InnerException property of SecondException but it appears it is not.
I'm not blocked on anything as I don't really need the FirstException to show up, I'm just rather intrigued about this behaviour.
Is there a way to know SecondException did get thrown first when
catching it all at upper level ?
If the first exception really is overriden by the second, what is the
reason ?
Does it happen in every other language ? Is it logical ?
I guess the primary explanation for why this works this way is that you are never catching your first exception and passing it along the chain. If you have a situation like the above where you may be throwing several exceptions on the way back to the original caller then you have to either catch them as they are thrown (and include them as an inner exception when creating the next one) :
Dim ex1 As Exception = Nothing
Try
Throw New Exception("first exception")
Catch ex As Exception
ex1 = ex
Finally
Throw New Exception("second exception", ex1)
End Try
Or, probably better - just don't throw until you have all of the exceptions figured out:
Dim ex1 As Exception = Nothing
Try
ex1 = New Exception("first exception")
Finally
Throw New Exception("second exception", ex1)
End Try
Throwing and catching exceptions is expensive, so it's probably best to not throw until you're ready to return and just log along the way.
One of the limitations of exception handling in .net is that there is no nice way for code in a Finally block to know what exception, if any, caused the code in the Try block to exit, nor is there any normal way for code in a finally block which does have such information to make it available to code which might throw an exception.
In vb.net, it's possible to kludge things in a manner that works pretty well, even though it looks a bit ugly.
Module ExceptionDemo
Function CopySecondArgToFirstAndReturnFalse(Of T)(ByRef dest As T, src As T) As Boolean
dest = src
Return False
End Function
Function AnnotateExceptionAndReturnFalse(ex As Exception, TryBlockException As Exception) As Boolean
If ex Is Nothing Then Return False ' Should never occur
If TryBlockException Is Nothing Then Return False ' No annotation is required
ex.Data("TryBlockException") = TryBlockException
Return False
End Function
Sub ExceptionTest(MainAction As Action, CleanupAction As Action)
Dim TryBlockException As Exception = Nothing
Try
MainAction()
Catch ex As Exception When CopySecondArgToFirstAndReturnFalse(TryBlockException, ex)
' This block never executes, but above grabs a ref to any exception that occurs
Finally
Try
CleanupAction()
Catch ex As Exception When AnnotateExceptionAndReturnFalse(ex, TryBlockException)
' This block never executes, but above performs necessary annotations
End Try
End Try
End Sub
Sub ExceptionTest2(Message As String, MainAction As Action, CleanupAction As Action)
Debug.Print("Exception test: {0}", Message)
Try
ExceptionTest(MainAction, CleanupAction)
Catch ex As Exception
Dim TryBlockException As Exception = Nothing
Debug.Print("Exception occurred:{0}", ex.ToString)
If ex.Data.Contains("TryBlockException") Then TryBlockException = TryCast(ex.Data("TryBlockException"), Exception)
If TryBlockException IsNot Nothing Then Debug.Print("TryBlockException was:{0}", TryBlockException.ToString)
End Try
Debug.Print("End test: {0}", Message)
End Sub
Sub ExceptionDemo()
Dim SuccessfulAction As Action = Sub()
Debug.Print("Successful action")
End Sub
Dim SuccessfulCleanup As Action = Sub()
Debug.Print("Cleanup is successful")
End Sub
Dim ThrowingAction As Action = Sub()
Debug.Print("Throwing in action")
Throw New InvalidOperationException("Can't make two plus two equal seven")
End Sub
Dim ThrowingCleanup As Action = Sub()
Debug.Print("Throwing in cleanup")
Throw New ArgumentException("That's not an argument--that's just contradiction")
End Sub
ExceptionTest2("Non-exception case", SuccessfulAction, SuccessfulCleanup)
ExceptionTest2("Exception in main; none in cleanup", ThrowingAction, SuccessfulCleanup)
ExceptionTest2("Exception in cleanup only", SuccessfulAction, ThrowingCleanup)
ExceptionTest2("Exception in main and cleanup", ThrowingAction, ThrowingCleanup)
End Sub
End Module
The module above starts with a couple helper modules which should probably be in their own "Exception helpers" module. The ExceptionTest method shows the pattern for code which might throw an exception in both the Try and Finally block. The ExceptionTest2 method calls ExceptionTest and reports what exception if any comes back from it. ExceptionDemo calls ExceptionTest2 in such a way as to cause exceptions in different combinations of the Try and Finally blocks.
As shown, if an exception occurs during cleanup, that exception will be returned to the caller, with the original exception being an item in its Data dictionary. An alternative pattern would be to catch the exception that occurs on cleanup and include it in the data of the original exception (which would be left uncaught). My general inclination is that it's probably better in many cases to propagate the exception that occurs during cleanup, since any code which was planning to deal with the original exception will probably expect that cleanup succeeded; if such an expectation cannot be met, the exception that escapes should probably not be the one the caller was expecting. Note also that the latter approach would require a slightly different method of adding information to the original exception, since an exception which is thrown in a nested Try block might need to hold information about multiple exceptions that were thrown in nested Finally blocks.

VB.net : how to close a form instantly?

i have this code on a form :
Function f1 as boolean
Try
------------
-----------
if condition
return true
else
return false
end if
Catch ex as Exception
Me.close
End try
End function
Private sub s1
if f1 then
instruction 1
else
instruction 2
end if
End sub
But if an exception occur inside f1 , the instruction Me.close
doesn't close the form instantly , but after
instruction 2 on s1 sub is executed.
How can i do to close the form instantly?
Thank you!
Depending on how you opened the form you should do a Me.dispose
Remarks from MSDN:
The two conditions when a form is not disposed on Close is when
(1) it is part of a multiple-document interface (MDI) application, and
the form is not visible; and
(2) you have displayed the form using
ShowDialog. In these cases, you will need to call Dispose manually to
mark all of the form's controls for garbage collection.
Me.Close() doesn't stop execution. Since you've handled the exception, execution continues after the call to f1. If you want execution to stop, you have to allow the exception to continue on:
Function f1 As Boolean
Try
'------------
'-----------
If condition Then
Return True
Else
Return False
End If
Catch ex As Exception
Me.Close()
Throw ' causes calling routines to stop executing as well
End Try
End Function