Introduction:
The .Net allows you to develop and use in your applications new user-defined controls, which can considerably simplify our coding. First of all we should define the kind of the control we want to discuss.
In Microsoft documentation it is specified that Windows Forms support three kinds of user-defined controls:
- Composite
- Extended
- Custom
A composite controls combine more than one Windows Forms control encapsulated in one unit (a common container). They inherit from the System.Windows.Forms.UserControl class and often are called user controls.
An extended control often are called derived or inherited control. We use this control when most of the functionality we need is already identical to an existing Windows Forms control. We just create a class that inherits from the class (Windows Forms control) we have chosen, and overrides or adds properties and methods.
A custom control should be created from the beginning by inheriting from the Control class. Here we are going to discuss composite user control (or in short: user control).
Using the BackgroundWorker Component allows to run an operation asynchronously. In this article I will show how you can use the BackgroundWorker Component with user controls. The examples are written using C#.
Let's create a small project, named "BGW_UC" (that stands for "BackgroundWorker Component and User Controls"). The project includes one windows form, named "Form1", and one folder, named "UC" (that stands for "User Controls"). First of all we add to the UC folder some base control, named "UC_0". Then we add two user controls ("UC_1" and "UC_2"), which inherit from the base control UC_0. You can make it by two ways: or by means of the inheritance picker (fig. 1) or simply to change a line of your code (List. 1):

Figure 1.
Namespace BGW_UC.UC
Partial Public Class UC_2
Inherits BGW_UC.UC.UC_0
'UserControl
Public Sub New()
InitializeComponent()
End Sub
End Class
End Namespace
List 1.
We add the BackgroundWorker Component (named "bgw") only to our base control. The UC_1 and UC_2 controls (the derived user controls) gain all the non-private data and behavior (including, of course, the bgw) of the base control (UC_0) in addition to any other data or behaviors they define for themselves.
As we have known, the BackgroundWorker Component has three events: DoWork, ProgressChanged and RunWorkerCompleted. We have to use these events in our controls. In addition to it, on some form, where we use our controls, we wish to catch the moment, when these events occur. With this purpose we, first of all, add to the UC_0 the events (for simplicity we add only two events):
Public Event BGWDoWork As EventHandler
Public Event BGWCompleted As EventHandler
Then we change default methods
Private Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
to
Protected Overridable Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
and so on.
The protected keyword allows to access method within its class and by derived classes, and the virtual keyword allows the methods to be overridden in derived classes. In order to run the RunWorkerAsync method of the BackgroundWorker Component we add the method:
Protected Sub RunWoker()
bgw.RunWorkerAsync()
End Sub
The full text (code) of our base control UC_0 will be the following:
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Namespace BGW_UC.UC
Partial Public Class UC_0
Inherits UserControl
Public Sub New()
InitializeComponent()
End Sub
#Region "ForClass"
Public Event BGWDoWork As EventHandler
Public Event BGWCompleted As EventHandler
#End Region
Protected Overridable Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
RaiseEvent BGWDoWork(Me, e)
End Sub
Protected Overridable Sub bgw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
End Sub
Protected Overridable Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
RaiseEvent BGWCompleted(Me, e)
End Sub
Protected Sub RunWoker()
bgw.RunWorkerAsync()
End Sub
End Class
End Namespace
OK! Everything is ready to add some functionality to the UC_1 and UC_2.
First of all we add the override methods bgw_DoWork, bgw_ProgressChanged and bgw_RunWorkerCompleted (List 2.).
Partial Public Class UC_1
Inherits BGW_UC.UC.UC_0
'User Control
Public Sub New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub bgw_DoWork(ByVal sender As Object, ByVal E As DoWorkEventArgs)
MyBase.bgw_DoWork(sender, E)
End Sub
Protected Overloads Overrides Sub (ByVal bgw_RunWorkerCompleted As bgw_RunWorkerCompleted)
End Sub
End Class
List 2.
To start our asynchronous operation we use for the UC_1 the method
Public Sub LoadData()
MyBase.RunWoker()
End Sub
And for the UC_2 the click_button event (preliminary having added the button1 to the UC_2):
Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
MyBase.RunWoker()
End Sub
In order to simulate database transactions (of course, you can connect to real database; this simulation is only for our test purpose) we use GetData.dll. With this purpose we add reference to GetData.dll and add two lines of code to the bgw_DoWork method:
Dim getData As New GetData.GetDataHelp ()
Dim dt As DataTable = getData.getDataSetCities(1000000).Tables(0)
The full text (code) of the UC_1 control will be the following:
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Namespace BGW_UC.UC
Partial Public Class UC_1
Inherits BGW_UC.UC.UC_0
Public Sub New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
MyBase.bgw_DoWork(sender, e)
Dim getData As New GetData.GetDataHelp()
Dim dt As DataTable = getData.getDataSetCities(1000000).Tables(0)
End Sub
Protected Overloads Overrides Sub bgw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
MyBase.bgw_ProgressChanged(sender, e)
End Sub
Protected Overloads Overrides Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
MyBase.bgw_RunWorkerCompleted(sender, e)
End Sub
Public Sub LoadData()
MyBase.RunWoker()
End Sub
End Class
End Namespace
The full text (code) of the UC_2 control will be the following:
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Drawing
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Namespace BGW_UC.UC
Partial Public Class UC_2
Inherits BGW_UC.UC.UC_0
'UserControl
Public Sub New()
InitializeComponent()
End Sub
Protected Overloads Overrides Sub bgw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
MyBase.bgw_DoWork(sender, e)
Dim getData As New GetData.GetDataHelp()
Dim dt As DataTable = getData.getDataSetCities(1000000).Tables(0)
End Sub
Protected Overloads Overrides Sub bgw_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
MyBase.bgw_ProgressChanged(sender, e)
End Sub
Protected Overloads Overrides Sub bgw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
MyBase.bgw_RunWorkerCompleted(sender, e)
End Sub
Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
MyBase.RunWoker()
End Sub
End Class
End Namespace
OK! Now we add to the Form1 the follow control: UC_1 (named "UC_11"), UC_2 (UC_21), button (button1), statusStrips (statusStrip1 and statusStrip2); to the statusStrip1 we add toolStripStatusLabel1 and to the statusStrip2-toolStripStatusLabel2.
To catch the beginning and finish of the data loading we use the BGWDoWork and BGMCompleted events (fig. 2):

Figure 2.
The full text (code) of the Form1 will be the following:
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Namespace BGW_UC
Partial Public Class Form1
Inherits Form
Public Sub New()
InitializeComponent()
End Sub
Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
uC_11.LoadData()
End Sub
Private Sub uC_11_BGWCompleted(ByVal sender As Object, ByVal e As EventArgs)
toolStripStatusLabel1.Text = "End...UC_1"
End Sub
Private Sub uC_11_BGWDoWork(ByVal sender As Object, ByVal e As EventArgs)
toolStripStatusLabel1.Text = "Load...UC_1"
End Sub
Private Sub uC_21_BGWCompleted(ByVal sender As Object, ByVal e As EventArgs)
toolStripStatusLabel2.Text = "End...UC_2"
End Sub
Private Sub uC_21_BGWDoWork(ByVal sender As Object, ByVal e As EventArgs)
toolStripStatusLabel2.Text = "Load...UC_2"
End Sub
End Class
End Namespace
As you can see, now we have possibility to test two independent time-consuming processes: the first one we start with the help of the button of the Form1 (for the UC_1), the second process we start with the help of the button of the control itself (for the UC_2). Run the project, click on the "Load UC_1" button. You can see that the first loading starts. But our user interface does not hang. Click on the "Load UC_2" button. Now two processes are running (fig. 3).

Figure 3.
In some seconds the first process comes to an end (fig. 4) and then the second (fig. 5).

Figure 4.

Figure 5.
NOTE: THIS ARTICLE IS CONVERTED FROM C# TO VB.NET USING A CONVERSION TOOL. ORIGINAL ARTICLE CAN BE FOUND ON C# Corner (http://www.c-sharpcorner.com/).