1

I have been banging my head against the wall all day trying to figure this one out.

I am finishing up a program to simply delete files in specific temp folders. I have read that it is sometimes good practice to create separate classes for methods and variables. So I have created a separate class for a couple methods to delete files and folders in a specified directory. I am using a Background Worker in my Form1 class and am calling my deleteFiles() method from my WebFixProcesses class in the DoWork event in the Form1 class. I am using a Background Worker so that I can easily report progress back to a progress bar on my main form.

The files get deleted without an issue but I just can't get the label on my main form to reflect the current file being deleted. the label doesn't change in any way. I know the formula is correct as I can get this working if the method is in the Form1 class. and I simply use:

 Invoke(Sub()
     lblStatus.Text = File.ToString
     lblStatus.Refresh()
 End Sub)

here is my method that I am calling from the WebFixProcesses class:

Public Shared Sub deleteFiles(ByVal fileLocation As String)
    For Each file As String In Directory.GetFiles(fileLocation)
        Try

            fileDisplay.Add(file)
            For i = 1 To fileDisplay.Count
                file = fileDisplay(i)
                Form1.BackgroundWorker1.ReportProgress(CInt(i / fileDisplay.Count) * 100)

            Next
            IO.File.Delete(file)                
            Form1.labelText(file)
            Form1.labelRefresh()

        Catch ex As Exception
            MessageBox.Show(ex.Message)
        End Try
    Next
End Sub

labelText() and labelRefresh() are methods from my main form which are using delegates to try to pass information to the control:

Public Sub labelText(ByVal file As String)
    If lblStatus.InvokeRequired Then
        Dim del As New txtBoxDelegate(AddressOf labelText)
        Me.Invoke(del, file)
    Else
                   lblStatus.Text = file.ToString()
    End If

End Sub
Public Sub labelRefresh()
    If lblStatus.InvokeRequired Then
        Dim del As New txtBoxRefDelegate(AddressOf labelRefresh)
        Me.Invoke(del)
    Else
                   lblStatus.Refresh()

    End If
End Sub

If anyone can help me out to inform me what I may be doing wrong it would be immensely appreciated as my head is in a lot of pain from this. And maybe I am going at it all wrong, and just being stubborn keeping my methods in their own class. But any help would be awesome. Thanks guys!

ganjeii
  • 1,168
  • 1
  • 15
  • 26
  • possible duplicate of [Progress Bar and Background Worker](http://stackoverflow.com/questions/27565851/progress-bar-and-background-worker) – Ňɏssa Pøngjǣrdenlarp Apr 02 '15 at 21:04
  • 2
    Standard VB.NET problem, we get them at a rate of about 2 a week. Always different code, always the same problem. Form1.labelText(file) is a bug, calling the labelText() method requires an *object reference*. But Form1 is not an object, it is a type. That this is still possible in VB.NET is a horrid compatibility hack. But it doesn't work when you use it in a worker thread, you get a *new* Form1 object. You can't see it and it is not the one you are looking at. You need a proper reference. – Hans Passant Apr 02 '15 at 22:23
  • Thanks for the reply Guys. Hans can u clarify your above comment in that you are stating that this is a bug with vb.net and I need to reference my Form1 class in a different way? If so, what would be the proper way to reference? I belive I have tried referencing with: Form1 mainForm As New Form1... still with no luck – ganjeii Apr 04 '15 at 02:17
  • Also tried: Form1 mainForm As Form1 with no luck – ganjeii Apr 04 '15 at 09:52

1 Answers1

1

What Hans wrote on the question comment is true: Form1 is a type, not an instance, but to make things easier to newbye programmes (coming from VB6), M$ did a "mix", allowing you to use the form name as the instance of the form in the main thread.

This however works only if you are on that thread.

If you reference Form1 from another thread, a new instance of Form1 is created.

To solve the issue, add this code to the form:

Private Shared _instance As Form1
Public ReadOnly Property Instance As Form1
    Get
        Return _instance
    End Get
End Property

We will use this property to store the current instance of the form. To do so, add this line to the Load event:

Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    _instance = Me

    'other code here
End Sub

Now, from every class, in any thread, if you use

Form1.Instance

...you get the actual form. Now you can Invoke, even from the same form:

    Me.instance.Invoke(Sub()
                           Me.lblStatus.Text = "Hello World"
                       End Sub)
JohnKiller
  • 2,008
  • 18
  • 28
  • 1
    Hey John that worked!!! bahhh thank you so much for that!! it will save me so much time in the future. I had read similar solutions but none as straight forward so that I understood exactly what was happening. Thanks again! I would vote up but my rep is still too low. – ganjeii Apr 06 '15 at 11:18