Resolved A usercontrol on a form with long running method on BackgroundWorker

Post number 10 has been selected as best answer.

aaaron123@roadrunner.com

Well-known member
Joined
Jan 23, 2011
Messages
47
Programming Experience
10+
I have a usercontrol on a form that contains a long running method.

I need the usercontrol to show on the form for the user to click something on it.

I also need to run a method that is on the usecontrol from a BackgroundWorker that is created by the form.

I think I'm up a creek without a paddle but 've seen magic o this site before so I thought I'd ask.

Is there any way??

Edited after the two replies.

Is this different than what I said before appeared to say?
 
Last edited:

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,319
Location
Sydney, Australia
Programming Experience
10+
So go ahead and do that. What's the actual problem? You design a user control in exactly the same way as you design a form, so you can add a Button and a BackgroundWorker the same way as always. You then add your user control to a form in exactly the same way as any other control. It seems to me that you have just assumed that you can't do this without even trying.
 

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,319
Location
Sydney, Australia
Programming Experience
10+
If you're saying, without actually saying, that you want the BackgroundWorker to be part of the form then go ahead and do that. You simply call the method on the user control from the DoWork event handler. Of course, just as always, you can't access the UI directly in the DoWork event handler or any method called from it. If you're saying, without actually saying, that that is the problem then there is no solution but to restructure the code. We shouldn't have to guess at this stuff though. You need to provide a FULL and CLEAR explanation of the problem.
 

aaaron123@roadrunner.com

Well-known member
Joined
Jan 23, 2011
Messages
47
Programming Experience
10+
If it wasn't clear it wasn't because I didn't try. Does the edit make it any better?

It's like the usercontrol does a GetFiles that that takes some time and the form wants to use the files which also takes a while.

So the form's Backgroundworker would like to call the usercontrol method that gets the files

Before then backgroundworker is created the user has to do something to the usercontrol to select which files to get.
 
Last edited:

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,319
Location
Sydney, Australia
Programming Experience
10+
That's clearer than it was but I still don't see what the issue is. If you want to call a method of the user control then call it. What is stopping you calling that method like you would call any other method? Surely you know how to call a method so please describe why calling this one is a problem.
 

Sheepings

Senior Programmer
Staff member
Joined
Mar 7, 2014
Messages
131
Location
UK
Programming Experience
10+

Sheepings

Senior Programmer
Staff member
Joined
Mar 7, 2014
Messages
131
Location
UK
Programming Experience
10+
Perhaps if you show us the relevant code you are struggling with, we might be of better assistance. What have you tried and where are you stuck?
 

aaaron123@roadrunner.com

Well-known member
Joined
Jan 23, 2011
Messages
47
Programming Experience
10+
I misinterpreted the problem. It's actually the SelectedNode statement that gives a "Cross-thread" error.
The usercontrol contains a TreeView
Just as you said the method did get called.

Public Function GetFileFullPathsFromSelectedFoldersTrees() As String()

If TreeView_Folders.SelectedNode Is Nothing Then



I believe there is a insert code icon but my big cursor icon covers the text that would have shown me which one.
 

Sheepings

Senior Programmer
Staff member
Joined
Mar 7, 2014
Messages
131
Location
UK
Programming Experience
10+
Please show us the relevant code you are having a problem with?
 

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,319
Location
Sydney, Australia
Programming Experience
10+
Like I said, you cannot access the UI from the DoWork event handler or any method called from it. The fact that you want to do that or you think you need to doesn't mean that you can. If you have code that may be executed on a secondary thread and that code accesses the UI then you need to restructure the code so the UI access is done on the UI thread regardless of which thread the rest of the code is executed on. For instance, if you have code like this:
VB.NET:
Dim str = TextBox1.Text
then, at the very least, you would need to change it to this:
VB.NET:
Dim str = CStr(TextBox1.Invoke(Function() TextBox1.Text))
 

aaaron123@roadrunner.com

Well-known member
Joined
Jan 23, 2011
Messages
47
Programming Experience
10+
Please show us the relevant code you are having a problem with?
In the user control this is the method that gets called

Public Function qGetFileFullPathsFromSelectedFoldersTrees() As String()

If TreeView_Folders.SelectedNode Is Nothing Then
...


In the form this is the calling code

Private Sub BackgroundWorker_11_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles mBackgroundWorker_11.DoWork

Dim editor As ControlTextEditor = DirectCast(e.Argument, ControlTextEditor)
Dim sourceFiePaths As String() = ControlFolderAndFileExplorer_1_11.qGetFileFullPathsFromSelectedFoldersTrees
...

If I give you, which I'd like to do, the complete worker and form code it would be pages of code.

I get a cross-thread error at the line:


If TreeView_Folders.SelectedNode Is Nothing Then
 

aaaron123@roadrunner.com

Well-known member
Joined
Jan 23, 2011
Messages
47
Programming Experience
10+
I've told you why that happens and I've told you how to avoid it. What's the problem?
The biggest problem is that I don't have much insight in this subject so I just barely understand the suggestions. But I believe you just told me, again, that I have to restructure the code. Something I don't expect you to do for me. And I don't have any idea how to do it myself, so I'll just have to avoid using the backgroundworker in this code.

Thanks for taking so much time with me.
 

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,319
Location
Sydney, Australia
Programming Experience
10+
Or you could do some research on the subject. For instance, my example uses the Invoke method of a TextBox. Did you try to find out what that method does? There is a lot of information out on the internet already. A lot of people seem to think that the only way to find out anything is to ask and have someone tell you. You can actually find information that's already out there on a subject.
 

aaaron123@roadrunner.com

Well-known member
Joined
Jan 23, 2011
Messages
47
Programming Experience
10+
I've used BackgroundWorked a few time with much more complex code than this without unresolved problems but this one stopped me. I looked at your code and if it solved this problem I missed it. I'll look again to see where it is applicable.

I just re-looked at your replies as realize I completely missed the invoke statement, sorry. I'll have to study that before I can say anything about it.
 

jmcilhinney

VB.NET Forum Moderator
Staff member
Joined
Aug 17, 2004
Messages
14,319
Location
Sydney, Australia
Programming Experience
10+
The complexity of the code is irrelevant. It's a very simple principle. Don't access the UI in code executed on a secondary thread. There are some control members that you can access with there being an issue but it's not easy to know which ones so the best thing is to just avoid any. If you're executing code on a secondary thread and you want to access the UI, you need to marshal a method call to the UI thread to do so. That's what the Invoke method does, which you ought to know by now because I already suggested that you look it up. The BackgroundWorker already provides a way to update the UI, i.e. the ReportProgress method and the ProgressChanged and RunWorkerCompleted events. They don't help you get data from the UI during the background work though.

You could also dump the BackgroundWorker altogether and use the Async/Await pattern, but that will take some research too.
 

Sheepings

Senior Programmer
Staff member
Joined
Mar 7, 2014
Messages
131
Location
UK
Programming Experience
10+
Take a look at the first code block only here : Answered - Read or get cell value (Excel)

That might give you an idea on how else you can do what you need. However, this method I provided works very similarly to what has already be explained to you above by using a background worker.

I suggest looking up the background worker documentation which I've already linked you on page #6 - You have no excuses now providing you read what has been given to you already, and that included all the docs on the background worker too. Until you actually try something, which involves altering your code as already explained to you, there is little more to explain, or little more we can do to help you. Post back when you make some changes?
 

aaaron123@roadrunner.com

Well-known member
Joined
Jan 23, 2011
Messages
47
Programming Experience
10+
Thanks. This is what I came up with. I would guess there is room for improvements. If it doesn't look useful its because I'm just a hobbyist interested in checking out things like this out so I try to use many variations. Unless I'm given reason to continue with this I'll move on to something else now.

Sorry I missed the Invoke statement in post 10. The only excuse I have is maybe because it was in bedded in black I subconsciously skipped over it like I skip over ads (best excuse I could come up with :)


VB.NET:
 Private Sub UpdateLableStateText()
        If mSourceFiePaths Is Nothing Then Exit Sub

        'If the method will only be called from a non-GUI thread there's no point in using InvokeRequired
        'But this method is called from both threads by design

        'Accessing a sub with parameters
        'Without using a lambda expression creating a Delegate Is required
        If mEditor.InvokeRequired Then
            Dim setTextCallbackDelegateObject As New SetTextCallbackDelegateType(AddressOf SetText)
            mEditor.Invoke(setTextCallbackDelegateObject, New Object() {sb__11.ToString})
        Else
            mEditor.TxtText = sb__11.ToString
        End If

        'Accessing a sub with parameters
        If Me.InvokeRequired Then
            'A lambda expressions used to create a delegate method on the fly:
            Me.Invoke(Sub() ChangeCount_11(mCount_11))
        Else
            Me.Invoke(Sub() ChangeCount_11(mCount_11))
        End If

        If Me.InvokeRequired Then
            'A lambda expressions used to create a delegate method on the fly:
            'Accessing a set property
            Me.Invoke(Sub() Label_Max_11.Text = CStr(mSourceFiePaths.Length))
        Else
            Me.Invoke(Sub() Label_Max_11.Text = CStr(mSourceFiePaths.Length))
        End If

        'Accessing a set property
        If Label_State__11.InvokeRequired Then
            'If called by the worker thread
            Label_State__11.Invoke(Sub() Label_State__11.Text = mLabelStateText_11)
        Else
            'If called by the UI thread
            Label_State__11.Text = mLabelStateText_11
        End If
    End Sub
 
Last edited:

JohnH

VB.NET Forum Moderator
Staff member
Joined
Dec 17, 2005
Messages
15,431
Location
Norway
Programming Experience
10+
A simpler pattern you can use:
VB.NET:
Private Sub UpdateUI() 'form method
    If InvokeRequired Then 
        Invoke(Sub() UpdateUI())
        Exit Sub
    End If

    'normal code, always in UI thread here.
End Sub
InvokeRequired and Invoke refers to current instance here. If called from different thread the method invokes itself on UI thread.
 

Sheepings

Senior Programmer
Staff member
Joined
Mar 7, 2014
Messages
131
Location
UK
Programming Experience
10+
The Implementation on p/#18 is very vague without seeing the whole example the OP wrote from thread start, to delegating back to the UI.

@OP I linked you that so you could get an understanding of how to navigate information back to your UI when running on a new thread as shown in my template code. You should also note; the background worker has a lot of added benefits too as explained on p/#16 regarding updating the UI from a background worker. While in theory they both do the same thing, its your call which implementation to use.

I would like to see your full implementation though, if you can share it?
 
Top Bottom