Posts filed under 'VB.NET Tutorials'
A common question that comes up rather often in VB discussion forums is how to pass data between forms. One of the common solutions offered are to use global variables in one way or another, for example, creating a module specifically for holding these values. These methods have all the typical problems with associated with globals. Another common strategy is to make the desired data available via properties on the forms. This can work in some cases but also can lead to undesirable interdependencies between forms. However, there is another approach that is often overlooked.
This article is about this overlooked strategy, overloading the New, Show or ShowDialog methods of forms. The reason this gets overlooked is that it isn’t obvious, particularly to someone who is new to programming or those who’ve transitioned from VB6. Forms get thought of as a special case because they contain a lot of generated code. But, actually, behind the scenes, they’re just another class in the application. And, like other classes, we can adapt them to our needs by overloading their base methods.
New
As with other classes with no explicit New method, a parameter-less New method of a form is automatically generated by the .NET compilation process. If we want to add our own overload method, we just add it to the code for it to our form. Here’s what it should look like:
Public Sub New(ByVal customerOrder As Order)
Me.InitializeComponent()
LoadOrder(customerOrder)
End Sub
In this example, we’re passing in an order object to our new form. Note that we call the InitializeComponent method first to create the controls on the form. This method is generated by VB.NET and is located in the [form name].Designer.vb file that contains a partial class definition for our form. Once the controls are created, we can then call our routine to load data into the controls.
When you define your own New method you will lose the default parameter-less New method and thus lose the VB.NET created default instance. To restore the default instance, add your own Public Sub New() as shown here:
Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
In Visual Studio, if you just type in the first line and press enter the rest will be generated for you. If you don’t add this routine, you will need to explicitly create instances of the form using your New method as in this example.
Dim frmCustomerOrder As New frmOrder(CurrentOrder)
You can use this way to insure that the form is properly loaded with data before it is displayed.
Show
Show, as you probably know, displays the form modelessly and does not return a value. This function comes with one overload which allows you to specify the owing window/form. To continue our example, let’s add a Show method that takes our order object.
Public Overloads Sub Show(ByVal customerOrder As Order)
If customerOrder Is Nothing Then
'load up order defaults
Else
'load from parameter
End If
MyBase.Show()
End Sub
Notice at the end we call the form’s base class to show the form. If you don’t have this line, then the form will not be displayed.
While the stock methods don’t return a value, did you know that you can write a version of this method that returns a value? You can. Here’s an example:
Public Overloads Function Show(ByVal OrderID As Guid, ByVal viewOnly As Boolean) As Boolean
If LoadCustomerOrder(OrderID) Then
SetupControls(viewOnly)
MyBase.Show()
Return True
Else
Return False
End If
End Function
In this example, we return a True if the order is found and the form is loaded but a False if the order ID isn’t found. Remember that processing doesn’t stop at the MyBase.Show() to wait for user input but continues onward.
ShowDialog
ShowDialog shows the target form modally and, in its built-in methods, it returns a Windows.Forms.DialogResult value. Here’s an example of overloading it
Public Overloads Function ShowDialog(ByRef newCustomerOrder As Order) As Windows.Forms.DialogResult
newCustomerOrder = New Order
'load up order defaults
Return MyBase.ShowDialog()
End Function
In this case we’re passing in an order object by reference so that the dialog can modify it and return it and we’re returning a DialogResult like the other overloads. Also, just like with the show method, we need to call the base class to show the dialog.
Note, however, that we don’t need to return the DialogResult value, we can return anything we want, as seen in this code that returns an order object.
Public Overloads Function ShowDialog(ByVal orderID As Guid) As Order
Dim ExistingCustomerOrder As New Order(orderID)
'load up order defaults
If ExistingCustomerOrder.OrderDetail IsNot Nothing Then
If MyBase.ShowDialog() = Windows.Forms.DialogResult.OK Then
Return ExistingCustomerOrder
Else
Return Nothing
End If
Else
Return Nothing
End If
End Function
It is probably best for consistency in most cases to return the same value as the default methods though.
That’s how you can pass values around between forms without having to use global variables (or work-alikes) or properties. Let me know if you have any questions, additions, or corrections by leaving me a comment.
Share This Article:
These icons link to social bookmarking sites where readers can share and discover new web pages.
September 28th, 2007
In .NET nullable data types are data types that can be set to a null reference or, in VB.NET terms, Nothing. They can either contain a value or have no value at all. Reference data types, like strings and classes, are nullable. However, Value types, such as integers and dates, are not nullable. If you set a value type to Nothing the result is a default value such as 0 for numeric types or #1/1/0001 12:00:00 AM# for dates.
As you can probably guess, there may be times when you will need to have value data types that can be Null/Nothing. For example, a database column of date values could be Null in the database and you want your class to reflect this situation. In the .NET Framework 2.0, we have the Nullable class and the Nullable structure that allows us to add the ability to have a value of Nothing to an underlying value type.
In practice, we will want to use the Nullable structure since it supports Generics and thus allows you to define a specific data type. This gives you greater type safety and it’s easier to work with.
To start things off, let’s create a fragment of a class that uses a Nullable structure as a property.
Public Class Orders
'
' Other property variables
'
Protected _orderShippedOn As Nullable(Of Date)
'
' Other methods and properties
'
Public Property OrderShippedOn() As Nullable(Of Date)
Get
Return _orderShippedOn
End Get
Set(ByVal value As Nullable(Of Date))
_orderShippedOn = value
End Set
End Property
End Class
In this example, we have an order shipped on date value. Since we will want the order in the system prior to shipping it out the door, the value in our database will be Null until this event happens. We don’t want to hard code values like this in several places in our application…
If CurrentOrder.OrderShipDate = #12:00:00 AM# Then
…to fake out null values. Instead, we wrapper our dates in a Nullable class.
HasValue and Value
But, you’ll notice that if you code a line like this…
If CurrentOrder.OrderShippedOn Is Nothing Then
…we’ll get an error. This is because we’re still dealing with a structure, not a class. Here’s what our code should look like:
If Not CurrentOrder.OrderShippedOn.HasValue Then
dtpOrderShipDate.Value = Now
Else
dtpOrderShipDate.Value = CurrentOrder.OrderShippedOn.Value
End If
The HasValue property returns a Boolean value that lets us know if there is a value or not. Then, when we want to retrieve the value to load it into a Date Time Picker control, we use the Value property. This allows us to return the correct type for the control. You can’t use = or Is to compare a Nullable type, you have to use the HasValue or Value properties.
Loading Nulls from the Database
Now let’s look at how we should load our object from our database. In this example, we’re assuming that we’re loading our object from a DataRow.
If orderDataRow.Item("ShipDate") Is DBNull.Value Then
_orderShippedOn = Nothing
Else
_orderShippedOn = CType(orderDataRow.Item("InventoryDate"), Date)
End If
We have to check for a Null value since we can’t convert a DBNull to a Date.
That’s it for this introduction to Nullable types. I hope you’ve found it useful. Let me know if you have any questions, additions, or corrections by leaving me a comment.
Share This Article:
These icons link to social bookmarking sites where readers can share and discover new web pages.
September 27th, 2007
The .NET Framework 2.0 BackgroundWorker class makes it easy to code simple threading into your applications. However, a common question that gets asked in VB related forums is, “How do I update a control, or controls, from the worker thread?”. Many people seem to be in search of a simple explanation of how to do this. In this article we’ll create a quick and easy example program that will walk you through the steps.
Getting Started
First, we will need to create a new Windows application. On our form we’ll add two buttons, btnStart and btnCancel, a progress bar, prgThread, and a listbox, lstValues. You may also want to import System.ComponentModel into the project namespace or onto the form or you can just spell it out like I’m doing below.
Next we’re going to add code. First, we declare the BackgroundWorker object, TestWorker. Note that we’re declaring it with events so that the event structure is built automatically.
'
Private WithEvents TestWorker As System.ComponentModel.BackgroundWorker
'
'
Now, code is added for the start button, btnStart.
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
btnStart.Enabled = False
btnCancel.Enabled = True
lstValues.Items.Clear()
prgThread.Value = 0
TestWorker = New System.ComponentModel.BackgroundWorker
TestWorker.WorkerReportsProgress = True
TestWorker.WorkerSupportsCancellation = True
TestWorker.RunWorkerAsync()
End Sub
First, we disable the start button and enable the cancel button. Next we reset the values for our listbox and and progressbar. Now we’re ready to create our BackgroundWorker object. Notice that we tell it that we want to have it report progress and support cancellation. Finally, we tell it to run the worker.
The Worker
Here’s the code for our worker thread. This code is contained in the DoWork event. All it’s doing is looping 100 times and reporting the progress and sleeping 100ms between iterations. We also check for a cancellation state.
Private Sub TestWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles TestWorker.DoWork
Dim ListText As String
For Value As Integer = 0 To 100
If TestWorker.CancellationPending Then
Exit For
End If
ListText = String.Concat("Item #", Value)
TestWorker.ReportProgress(Value, ListText)
Threading.Thread.Sleep(100)
Next
End Sub
You can also see that in the ReportProgress function call that we’re passing in the current value and a string.
Updating Form Controls
In the ProgressChanged event, we get to process our values from our DoWork method. Here’s the code:
Private Sub TestWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles TestWorker.ProgressChanged
prgThread.Value = e.ProgressPercentage
lstValues.Items.Add(e.UserState)
End Sub
'
In this routine, the progress bar and the listbox are updated with values from the worker thread. Remember that the UserState value is an object and will require conversion if you can’t use an object type.
Canceling the Worker
Now, what if you want to cancel the worker? Here’s the code that goes into our cancel button’s Click event:
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
TestWorker.CancelAsync()
End Sub
'
'
Here we call the CancelAsync method. However, this only sets a flag and, as shown above, our DoWork method has to check for a CancellationPending state. Otherwise, the work will continue until the DoWork routine is exited.
Finishing Things Up
When the work has been completed or canceled, the RunWorkerCompleted method is called. In our program, this allows us to reset our buttons.
Private Sub TestWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles TestWorker.RunWorkerCompleted
btnStart.Enabled = True
btnCancel.Enabled = False
End Sub
That’s how it’s done in a nutshell. Of course, handling multi-threading in your applications can become very tricky. It is recommended that you further review how to avoid problems with threading before implementing it.
Let me know if you have any questions about BackgroundWorker or if you have any suggestions or thoughts about this example by leaving me a comment.
Share This Article:
These icons link to social bookmarking sites where readers can share and discover new web pages.
September 24th, 2007
My.Computer.Network is another VB.NET My Namespace shortcut class that you can use to handle simple network and Internet operations. In this article we’ll examine the basics of this class with some code examples along the way.
These functions are essentially easy-to-use wrappers for objects found in the System.Net namespace. If you need more than what this class provides then you should look there.
IsAvailable
As you might guess, this property indicates if there is an available network connection or not. The hitch with this function is that it doesn’t tell you much about the connection, it only says if the computer has one or not. For example, a computer might have a local network connection but the Internet connection could be down but this property would return True. Therefore, you should combine this technique with the Ping function to insure that a remote location is available as seen in this code example:
If My.Computer.Network.IsAvailable Then
If My.Computer.Network.Ping("192.168.100.1") Then
My.Computer.Network.UploadFile(LocalFileName, RemoteAddress)
End If
End If
NetworkAvailabilityChanged
This event is raised when the network connectivity changes but, like IsAvailable, it’s not capable of distinguishing between local and remote changes. Therefore, it really isn’t that useful in many situations. It might be handy in a web service client app, for example, a single computer at a remote small store location without a permanent or iffy Internet connection.
This event is built into the MyApplication partial friend class so, if you’re using the Windows Application Framework you just have to add code to the following built-in routine:
Partial Friend Class MyApplication
Private Sub MyApplication_NetworkAvailabilityChanged(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.Devices.NetworkAvailableEventArgs) Handles Me.NetworkAvailabilityChanged
If My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping("192.168.100.1") Then
'code to handle/report connection available
Else
'code to handle/report connection down
End If
End Sub
End Class
Ping
As we see in the code examples above Ping does a simple check to see if a remote target computer responds and returns a boolean saying if the check was successful or not. You can use an IP address, like in the examples above, or a DNS resolvable name. This means that for Internet addresses you would not include protocol prefixes like “http://” or “ftp://” but only the name. You can also provide a timeout for the ping in milliseconds and the default is 500ms, a half-second. Increasing this value can be useful if you’re dealing with a slow dial-up connection. Always verify any user input for this call to prevent unwanted exceptions. Note that some servers use firewalls and other methods to protect themselves against ping attacks and the function may return a False when there actually is a system at that address.
Here are some examples of this function:
If My.Computer.Network.Ping("192.168.100.1") Then
...
If My.Computer.Network.Ping("192.168.100.1", 2000) Then
...
If My.Computer.Network.Ping("vbnotebookfor.net") Then
....
If My.Computer.Network.Ping("www.google.com") Then
...
' Will Cause PingException
If My.Computer.Network.Ping("http://www.google.com") Then
DownloadFile and UploadFile
Download, of course, copies a file from a remote location to a local location while Upload does the opposite. Overloads provide several options beyond just the file names or URLs. As with regular file copies the source and target locations have to be accessible or an exception will occur. Therefore, it’s a good idea to do some basic validation before calling either of these routines. Unlike the Ping function, you do need to include a protocol such as “http://” or “ftp://”.
There are overloads for credentials. You can use either clear text username and password parameters (not recommended when you’re transmitting sensitive information!) or, if you’re connecting to a system that supports it, an ICredentials object.
Both have a connection timeout value with a default of 100 seconds. Remember this value is in milliseconds though. As with Ping, this parameter is useful when you have slow conditions.
Both also provide a user interface option where the user will be shown a progress dialog and can cancel the transfer. You will want to set an action to be taken when the user cancels since the default is an exception.
Download also has an option for you to specify if a local file can be overwritten or not. Upload doesn’t offer this so you may get back exceptions if the remote server doesn’t permit the overwrite. It is important to check for exceptions in these methods since there are so many things that can go wrong with remote file transfers.
Here are some simple code examples:
1. Upload file with exception handling, connectivity check, clear text username/password, and showing UI
Try
If My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(RemoteServer) Then
My.Computer.Network.UploadFile(LocalFile, RemoteLocation, UserName, Password, True, 10000)
End If
Catch ex As Exception
'exception handling code here
End Try
2. Download file with exception handling and connectivity check
Try
If My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(RemoteServer) Then
My.Computer.Network.DownloadFile(RemoteLocation, LocalFile)
End If
Catch ex As Exception
'exception handling code here
End Try
3. Upload file with exception handling, connectivity check and the current user’s credentials
Try
If My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(RemoteServer) Then
My.Computer.Network.UploadFile(LocalFile, RemoteLocation, My.User.CurrentPrincipal)
End If
Catch ex As Exception
'exception handling code here
End Try
I hope you’ve found this introductory overview of the My.Computer.Network class useful. If you have anything to add or if you have any questions, please feel free to leave me a comment.
Share This Article:
These icons link to social bookmarking sites where readers can share and discover new web pages.
September 21st, 2007
The .NET math class provides you with several handy math routines you can use even if you’re not doing complex trigonometric or logarithmic functions. In this article we will take an introductory look at the non-trig, non-log, functions and how to use them in your code.
Abs
This is an old familiar command to VB Classic and BASIC programmers. It returns the absolute value of a number and it accepts SByte, Short, Integer, Long, Decimal, Single, and Double data types in its overloads. Remember it returns the same type of data that you send it. It doesn’t do conversions between numeric types like previous versions of VB and BASIC when you have Option Strict On (which you should always have on). You’ll need to handle the conversion yourself.
Also, don’t forget that you have to prefix it with Math or use “Imports System.Math” in your module or project namespace. Here’s an example of this function:
Dim NewValue As Integer = Math.Abs(OldValue)
BigMul
If you’re working with big integers this function can be quite helpful in helping you avoid overflow exceptions. Remember the product of multiplying two Int32 values is an Int32 value. If your product exceeds the upper or lower Int32 range you’ll get an exception. To avoid this situation, you can use BigMul to multiply two Int32 values and return a Int64 value. Here’s a simple example:
Dim ABigNumber As Integer = 40000000
Dim AnotherBigNumber As Integer = 40000000
Dim ABigProduct As Int64 = Math.BigMul(ABigNumber, AnotherBigNumber)
DivRem
First BigMul and now DivRem, did somebody at Microsoft not get the memo about using meaningful function names? Anyway, DivRem calculates and returns the quotient of two integers, either 32 or 64 bit, plus it also returns the remainder in an output parameter. This function is handy if you want to get both the quotient and remainder in a single swoop. Here’s an example:
Dim TestIt As Integer = 578
Dim TestToo As Integer = 75
Dim TestValue As Integer
Dim TestRemainder As Integer
TestValue = Math.DivRem(TestIt, TestToo, TestRemainder)
Debug.Print(String.Concat(TestValue, " | ", TestRemainder))
Output Value: 7 | 53
Remember to make sure that you don’t accidentally divide by zero here.
IEEERemainder
This function is sort of like DivRem except that it’s for doubles and that it returns the remainder, not the quotient (which gets dropped). Kind of an inconsistant design if you ask me. Here’s an example of this function:
Dim TestAgain As Double = 194.89482
Dim RemainderTest As Double = Math.IEEERemainder(TestAgain, Math.PI)
Output Value: 0.116075477432837
Note the use of the Pi constant value in this example.
Sign
Sign is a simple, straightforward function. It returns -1 if the target number is negative, 0 if the number is zero, and 1 if the number is positive. There are overloads that will work with any of the signed number types. Here’s an example:
Select Case Math.Sign(TestAgain)
Case 1
'positive number action
Case 0
'zero action
Case -1
'negative number action
End Select
Ceiling and Floor
These functions are useful with decimal and double values where you want to obtain the nearest whole number that’s either greater than (ceiling) or less than (floor) of the given number. This could be useful in a custom rounding routine. Here are some examples and the result of the operation
Dim MyValue as Double
MyValue = Math.Ceiling(194.89482)
Output Value: 195
MyValue = Math.Floor(194.89482)
Output Value: 194
MyValue = Math.Ceiling(-194.89482)
Output Value: -194
MyValue = Math.Floor(-194.89482)
Output Value: -195
Truncate
Truncate is like the old VB6/MSBASIC Fix function (this function is still in the Microsoft.VisualBasic Namespace). It simply drops the decimal portion of the target decimal or double number. Here’s the example
Dim IntValue As Integer = CInt(Math.Truncate(TestAgain))
Notice that this function also returns a double or decimal rather than an integer and this requires conversion unless you’re unwisely not using Option Strict On.
Max and Min
These functions respectively return the larger or lesser of the two numbers passed in. These functions could be quite useful for sorting routines or for random selection routines.
LowestPrice = Math.Min(NewProduct.Price, OldProduct.Price)
Pow
Pow simply raises an number to a specified power, just like the ^ operator does. I’d just use the operator myself.
Debug.Print(String.Concat(7 ^ 8))
Debug.Print(String.Concat(Math.Pow(7, 8)))
Output Value for both: 5764801
Round
I covered Round in depth in this earlier article: What You Should Know About Rounding in VB.NET
I hope this article has given you a good overview of the Math class functions. While there is some redundancy there are few hidden gems as well. As always, let me know what you think by leaving a comment.
Share This Article:
These icons link to social bookmarking sites where readers can share and discover new web pages.
September 19th, 2007
Next Posts
Previous Posts