Advanced Basics

Windows Forms Q&A

Ken Spencer

Code download available at: AdvancedBasics0312.exe (131 KB)
Browse the Code Online

Q I have been playing with console applications in Visual Basic® .NET. I would like to know if it is possible to gather the variables upon calling the application, rather than asking for input when it is running (for example, TestApp.exe Variable1 Variable2)?

Q I have been playing with console applications in Visual Basic® .NET. I would like to know if it is possible to gather the variables upon calling the application, rather than asking for input when it is running (for example, TestApp.exe Variable1 Variable2)?

A There are at least two ways to obtain the command-line parameters from an application. It doesn't matter whether it's a GUI or console application, the code is the same. Let's try accessing the parameters in a Windows®-based application.

A There are at least two ways to obtain the command-line parameters from an application. It doesn't matter whether it's a GUI or console application, the code is the same. Let's try accessing the parameters in a Windows®-based application.

Figure 1 Debugging Options

Figure 1** Debugging Options **

First, Visual Studio® .NET makes it easy to work with command-line parameters as you build and test your application. You can set parameters in the development environment and then test your application by running it from Visual Studio .NET. Then when you run the application outside of the development environment, the real parameters are used by your code. Figure 1 shows the debugging options dialog where you can set the parameters. Once the parameters are set in the options, you can write code to access them. Figure 2 shows code that accesses the parameters in Sub Main, the startup function. The parameters are passed into the application automatically, as you can see from the Sub Main definition shown here:

Sub Main(ByVal argv As String())

Since argv is an array, you can access the values as you would any other array element, as shown in Figure 2.

Figure 2 Accessing Params in Sub Main

Module modMain
Sub Main(ByVal argv As String())
Dim oParam As String
Dim frmMain As New Form1
    For Each oParam In argv
        If frmMain.txtCommandLineParams.Text <> "" Then
            frmMain.txtCommandLineParams.Text &= vbCrLf
        End If
        frmMain.txtCommandLineParams.Text &= oParam.ToString()
Next
frmMain.ShowDialog()
End Sub
End Module

Figure 3 shows my favorite way to access the parameters. The Environment class makes it easy to access the command-line parameters from anywhere in your application. It is a rich class that lets you discover a tremendous amount of information, including an app's command-line parameters. You can gain access to these parameters by calling the GetCommandLineArgs method, as shown in Figure 3 and in the following console application code:

Sub Main()
Dim CommandLineArguments As String() = _
    Environment.GetCommandLineArgs()
Dim i As Integer

For i = 0 To CommandLineArguments.GetUpperBound(0)
    Console.WriteLine(CommandLineArguments(i) & vbCrLf)
Next
End Sub

This function returns an array which you can process to obtain the values. The first element in the array is the full path name of the application. The code shows the parameters in the console window.

Figure 3 Accessing Params with Environment

Private Sub cmdGetParams_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles cmdGetParams.Click
Dim CommandLineArguments As String() = _
    Environment.GetCommandLineArgs()
Dim i As Integer

txtCommandLineParams.ResetText()
For i = 0 To CommandLineArguments.GetUpperBound(0)
    If txtCommandLineParams.Text <> "" Then
        txtCommandLineParams.Text &= vbCrLf
    End If
    txtCommandLineParams.Text &= CommandLineArguments(i)
Next

End Sub

Q If I have a project which is only retrieving data from a database and displaying that data on a form, do I need to have the Connection.Adapter object on each form? I have many forms and lots of queries, so how do I execute these queries?

Q If I have a project which is only retrieving data from a database and displaying that data on a form, do I need to have the Connection.Adapter object on each form? I have many forms and lots of queries, so how do I execute these queries?

A There are many ways you can architect an application. I am a big fan of splitting code apart into discrete modules or classes where the code is easier to work with. Let's see how.

A There are many ways you can architect an application. I am a big fan of splitting code apart into discrete modules or classes where the code is easier to work with. Let's see how.

Figure 4 shows a simple module with one function. The function contains code that executes a SQL statement and returns a DataSet. You can drop it into a module in a project and then use it as shown here:

Dim ds As DataSet
Dim sSQL As String

sSQL = "Select * from customers"
'Get a dataset from the SQL above
ds = RunSQLWithDataSet(sSQL)

'Set the DataSource of the grid to table 0 from ds
DataGrid1.DataSource = ds.Tables(0)

This lets you to separate your data access code from your interface code. Then you can add other functions that perform other data-related tasks and call them as needed.

Figure 4 General Database Query

Module modData
Const ConnectionString = "server=localhost;database=NorthWind"

Public Function RunSQLWithDataSet(ByVal sSQL As String) As DataSet

Dim oDataSet As New DataSet
Dim oDataAdapter As SqlClient.SqlDataAdapter

Try
    'Create New DataAdapter 
    oDataAdapter = New SqlClient.SqlDataAdapter( sSQL, ConnectionString)

    'Fill DataSet from DataAdapter
    oDataAdapter.Fill(oDataSet, "Table1")

    'Set return value of function
    Return oDataSet
    Catch e As Exception
    Throw New Exception( "An exception occurred in RunSQLWithDataSet", e)
        Finally
        End Try
    End Function
End Module

The RunSQLWithDataSet function creates the data connection using a data adapter and simply returns a DataSet. This allows you to call the function over and over from your application without the need to create any data adapters or connections in a form or other code. Instead, you simply create the SQL you want to execute:

sSQL = "Select * from customers"
ds = RunSQLWithDataSet(sSQL)

Now your code can use the new ds DataSet in order to access the data that's returned.

For a more powerful and easier way to accomplish data access, Microsoft has created something called a data access application block for these tasks. This is a well-built and tested component that can perform just about all of your data needs. The component has features for executing stored procedures or SQL queries and allows you to easily specify parameter details for stored procedures. For more information, see Data Access Application Block.

Microsoft has also created a number of other application blocks and they are continually adding more, so check back often.

Q I want to design two forms using Visual Basic .NET. The first form has one checkbox and the second form has an Enter button. When the checkbox is checked and the Enter button is clicked, how can I get the information that's on the first form to show up on the second form?

Q I want to design two forms using Visual Basic .NET. The first form has one checkbox and the second form has an Enter button. When the checkbox is checked and the Enter button is clicked, how can I get the information that's on the first form to show up on the second form?

A Windows Forms do not behave exactly like Visual Basic 6.0 forms. In Visual Basic 6.0, you could access properties on other forms automatically. Not so in Visual Basic .NET; now you must treat everything like an object.

A Windows Forms do not behave exactly like Visual Basic 6.0 forms. In Visual Basic 6.0, you could access properties on other forms automatically. Not so in Visual Basic .NET; now you must treat everything like an object.

Once you understand that forms are objects, then you can manipulate them in many different ways. Let's take a look at your question and see how to communicate between two forms. One approach is to pass the data into the new form when you display it. Figure 5 shows this approach.

Figure 5 PassingVarData_Load

Dim NewData As String

Sub New(ByVal IncomingData As String)
    'This call is required by the Windows Forms Designer.
    InitializeComponent()

    NewData = IncomingData
End Sub

Private Sub PassingVarData_Load(ByVal sender As _
    System.Object, ByVal e As System.EventArgs) _
    Handles MyBase.Load

    txtTitle.Text = NewData
End Sub

The first step is to create a form-level variable for the new data:

Dim NewData As String

The second step is to create a new constructor for the form. This code simply creates a constructor that takes the new parameter. Then the code calls the InitializeComponent method to perform all the normal startup functions for the form and sets the NewData variable to the value that's passed in when the form is created:

Sub New(ByVal IncomingData As String)
    'This call is required by the Windows Forms Designer.
    InitializeComponent()
    NewData = IncomingData
End Sub

Then in the Form_Load event, the NewData variable is used to load the textbox. The first two lines of code show how to call the form and pass the data (Me.Text) to the constructor:

Dim frm As PassingVarData
frm = New PassingVarData(Me.Text)
frm.txtOutput.Text = txtCommandLineParams.Text

frm.ShowDialog()

This approach works well when you can pass data to the form when the form is created, but what if you must communicate between two forms once the forms are already created? This may mean that you pass data from one form to the other or that you must communicate back and forth between two or more forms.

This code also shows another approach that allows you to communicate with a form element. Once you have created the instance of the new form, you can access the form's controls directly, as shown in the following line:

frm.txtOutput.Text = txtCommandLineParams.Text

In this case, you simply prefix the control or property you want to access with a variable that points to the instance of the form. This, of course, means you must keep a variable in scope if you want to continue to communicate with the form. In this example, you could move the definition for the form to a form-level global variable, giving you continued access to the form's controls. If you move the definition to a friend or public variable, then you can access the form from anywhere in your application. You can also store references to forms in arrays, collections, and in a variety of other ways to allow you to store groups of forms for later reference.

While you can find a tremendous amount of information on the Internet about developing applications using the .NET Framework, it's not always organized so you can find it easily. So, just because you don't see something on the Internet, don't assume it's not possible or that it's not there somewhere. The MSDN® Help feature in Visual Studio is a great place to start for most questions because the index is pretty good. When I needed to create a queue to store information in a client's application, I fired up MSDN Help and entered "queue" in the index. Boy, was I surprised to find the Queue class, which of course saved lots of time.

Send your questions and comments for Ken to  basics@microsoft.com.

Ken Spencer works for 32X Tech (https://www.32X.com), where he provides training, software development, and consulting services on Microsoft technologies.