Posts filed under 'Tip Sheets'
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.
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)
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.
' Add any initialization after the InitializeComponent() call.
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, 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
'load from parameter
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
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 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
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
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.
September 28th, 2007
My articles on using Strings in VB.NET have been rather popular and appreciated so here’s another one. This time we’ll look at 3 quick and useful tips for using Strings. These are simple but they’re often overlooked, particularly by those new to VB.NET. Hopefully these tips will help you prevent errors in your code and improve performance.
1. Watch Your String Length and Indexes
Previous versions of VB and BASIC in general used one based strings for functions. Some of the Microsoft.VisualBasic Namespace String functions, such as Mid, still are this way. However, if you’re working with the .NET string functions you must always keep in mind that you’re really dealing with a zero based character array behind the scenes. This means that any index value you use must be zero or greater and can’t be greater than or equal to the length of the string. Always check your length before performing string functions like SubString to prevent costly exceptions.
2. Nothing vs. String.Empty
Do you know the difference between a string variable equal to Nothing and one equal to an empty string? Nothing means that the variable does not have an object associated with it while String.Empty means that there is an object that is set to an empty string. Remember that String variables are always Nothing when you declare them unless you initialized them at that point. If you try to use a string variable that has a value of Nothing you will get a Null Reference Exception. I’ve seen this little bug pop up often in property routines and their associated variables.
3. LastIndexOf vs. IndexOf
A common point of confusing with these functions is with the extra parameter overloads where only part of a string is being considered. First of all, go back to tip #1, know the length of the string so that you won’t get a ArgumentOutOfRange exception. Remember that the IndexOf search moves from the start of the string to the end of the string while LastIndexOf searches from the end to the start. This would mean that the first call below would cause an exception while the second one would be OK.
Dim Test As String = "abcdefghijklmnopabcdefghijklmnop"
Dim Position As Integer
Position = Test.IndexOf("abc", 24, 10) 'throws exception
Position = Test.LastIndexOf("abc", 24, 10) 'OK
I hope you found these ideas helpful. If you have some of your own you would like to add or if you have questions or observations about these tips, please leave a comment.
September 18th, 2007
Converting a string to an integer is a common operation and there are several ways to do this in VB.NET. In this article, we’ll take a look at several of them and compare them and, perhaps, arrive at the best all round way to perform this operation.
I’ll be rating each function on 3 factors: Usability, Flexibility and Performance. Usability indicates how easy it is for the average programmer to understand how to use it and get the desired results. Flexibility is how many overloads are available for it and how well it integrates with the rest of VB.NET and the .NET world as a whole. Performance is how well the function does in my speed test, a loop of 10000 iterations calling the function with a string variable equal to “1000″. Each criteria is on a scale of 1 to 5 with 5 being the best.
Val is the venerable BASIC conversion command. It’s been around since the very early days of the BASIC language in the mid to late 1960s. In older versions of MSBASIC it was the only game in town when it came to conversions. It’s still in VB.NET, as a member of the Microsoft.VisualBasic.Conversion namespace, and it really hasn’t changed much from the old days. It reads in a string and looks for numerics or numeric modifiers (”.”, “+”, “-”, “&H”, “&O”). It strips out whitespace characters as it goes and it stops on the first character that’s not numeric according to its criteria. It returns a double, not an integer, so, if you’re running Option Strict like you should, an extra conversion step is needed to make an integer. It also cannot interpret cultural information, such as different decimal separators.
MyDouble = Val(MyString)
Usability: Programmers moving over from VB6 or earlier BASIC may be familiar with it and its quirks but its conversion methods can easily introduce unexpected bugs into a program. Rating: 2
Flexibility: It has 3 overloads, accepting a String, Char, or Object. It won’t throw an exception except in the case of an unconvertable object or an overflow error. Rating: 3
Performance: Amazingly, Val turned in the fastest performance in my testing, beating out the other methods. It was 3 times faster than Parse and nearly 6 times faster than CInt. It’s a 60’s muscle car of a function, fast on the straight track but not so great on curves. Rating: 5
CInt is another classic MSBASIC conversion method. It hasn’t been around quite as long as Val but made its debut in the 1980’s in QuickBasic. One ‘old school’ difference between it and VAl is that it will throw an error if the string in question can’t be converted. Unlike Val, it is part of the core VB.NET language and is not, as some mistakenly believe, part of the much maligned Microsoft.VisualBasic namespace.
MyInteger = CInt(MyString)
Usability: It’s an easy and familar command that’s very straightforward to use and quite readable. It uses “Banker’s Rounding” to round off fractions, which can be a plus or minus depending on your perspective. Rating: 4
Flexibility: It takes an Object as a parameter which makes it somewhat flexible, perhaps too much so. It does handle the current cultural settings fine but you can’t use alternative providers. Rating 3
Performance: MSDN recommends that you use CInt and the other ‘C’ conversion functions because they’re optimized for VB.NET code. To my surprise, my testing didn’t show this optimization. Instead, it turned in the slowest time of all the functions. Rating: 1
Parse is a new .NET function built into the numeric data types. If you want to do things the .NET way, it’s your ticket. And, as we’ll see below, it’s quite flexible.
MyInteger = Integer.Parse(MyString)
Usability: This function, while something new to .NET newbies, is easy enough to understand for novices. For experienced VB.NET programmers the flexibility makes it a good choice: Rating: 5
Flexibility: It has 4 overloads which allow it to accept FormatProviders and NumberStyles, making it quite flexible. The ability to use FormatProviders makes it very adaptable to applications that need to be globally aware. The NumberStyles allow acceptable character combinations to be precisely defined. The only flexibility downside is that a bad entry will cause a time consuming exception. Rating: 5
Performance: This function, while not as fast as Val, is twice as fast as CInt. Rating: 4
TryParse is brand new in the .NET Framework 2.0. It is like its cousin, Parse, with a few differences. Most notably, it does not throw an exception if the function fails, instead it returns a False. Returns a False, not an integer? That’s right, the return value from the function is a success/fail Boolean while the integer variable is passed into the function ByRef and modified by the function.
Usability: This function is a little confusing at first, since it returns a Boolean, but easily becomes comfortable. Since it doesn’t throw an exception on bad data, it can be more useful than Parse in some situations. Rating: 4
Flexibility: It has 2 overloads, the second allows it to accept FormatProviders and NumberStyles, just like Parse does. The only downside is that you can’t supply one or the other parameter, both must be specified. Rating: 5
Performance: This function returned performance numbers virtually identical to it’s cousin. It’s nimble avoidance of a potential exception slow down gives it a slight edge. Rating: 5
The Convert object in .NET is used to convert one data type into another data type and, of course, the ability to convert a String to an Integer, or Int32 in our case, is provided.
MyInteger = Convert.ToInt32(MyString)
Usability: This number of overloads for this function might be a little intimidating to some at first glance but it is rather straight forward in how it works. Bad data will throw an exception.: Rating: 5
Flexibility: ToInt32 has a whopping 19 overloads that allow it to convert just about another other data type. It can also use FormatProviders but not NumberStyles. Rating: 5
Performance: This function is about 20% slower than the Parse and TryParse functions, probably because it is doing more internally. Rating: 3
That covers the major conversion methods. There are a few others out there that I didn’t cover, such as using Regular Expressions to convert, or coding your own conversion. If you think there is one I should have covered but I didn’t, please let me know in a comment.
Now let’s look at which function is the winner of our comparison by looking at the total score.
Val - 10 Points
CInt - 8 Points
Parse - 14 Points
TryParse - 14 Points
Convert.ToInt32 - 13 Points
Parse and TryParse tie! The deciding factor of which of these to use would probably depend on your code. I tend to favor TryParse myself since it handles exceptions so gracefully so I’ll give it the tie breaker win.
CInt really turned out to be a disappointment performance-wise. I have defended this function on a few occasions when some people didn’t know it was part of the core VB.NET language. While I can still defend it on that count, its poor performance makes me not recommend it. I will note that its conversion speed was much faster for doing number to number data type conversions so this speed hit seems to be only associated with string conversions.
While I can’t recommend the use of Val due to it’s hinky conversion rules, its performance was quite surprising. It would be interesting to see how it was implemented internally.
Well, that’s it for this comparison test. Have you run any tests and gotten different results? What are your thoughts on string to integer conversion in VB.NET? Any questions? Leave me a comment.
September 14th, 2007
A common question encountered in VB related forums, where some members are new to OOP, concerns what criteria one should use to discover the objects that fit into your solution’s design. In this article, we will look at several methods you can use to identify objects from your requirements. I’m going to take an Eastern approach so brew yourself a cup of green tea first and then start reading.
It is like a finger pointing away to the moon. Do not concentrate on the finger or you will miss all that heavenly glory. - Bruce Lee
To often programmers become fixated on the particulars of the code. For example, how they should write a Create, Update, Read, and Delete (CRUD) sequence or if they should use an integer or a long for a particular property. This is ‘concentrating on the finger’ when it comes to discovering objects. At this point in the design, don’t focus on how you will implement the particulars. Instead, look at the whole of the object and how it interacts with other objects in the system and the world at large.
The pine’s shadow is dark
Exactly as the moonlight is bright. - Kodo Sawaki
One objective in object discovery is to discover commonality between your objects. Sometimes this may not be entirely obvious so it requires one to let go of the obvious at look at things a different way. The goal is to find these points of intersection and, where applicable, use an abstract base class or interface to express this relationship.
One moon shows in every pool, in every pool the one moon. - Zen saying
Another idea along the same lines as the last is to look for things that are duplicated in the design and how they’re duplicated. This will often suggest objects and relationships between objects that you can use in various ways.
In thinking, keep to the simple. - Lao-tzu
Look for the least common denominator, the smallest unit, in your system. A common problem is defining an object too large and then having to break it down into smaller parts. This can result in bad code. Try to do this analysis early on in your design to prevent such problems.
When you have names and forms, know that they are provisional. - Lao-tzu
Separate methods and properties that will change from those that won’t change. Of course, change is almost inevitable but you can make educated judgments as to which things are the most likely to change. Try to keep the elements that will change out of your base classes and interfaces as much as possible. This process can help you further define and separate them.
We shape clay into a pot,
but it is the emptiness inside
that holds whatever we want. - Lao-tzu
Examine the data your system will need to access, particularly if you’re working with legacy data or a pre-existing database design. This will often suggest objects or additions to your existing objects.
When people see some things as beautiful, other things become ugly.
When people see some things as good, other things become bad.
Being and non-being create each other. - Lao-tzu
Imagine your classes as though they already existed and consider situations where you might use an instance of them. How would you write your code to work with them? What would their constructor and destructor routines (New and Finalize in VB.NET) need? What methods and properties would you need? Do you think the object could be extended easily? How tightly is it tied to your other objects? If you needed to write a subclass could this class act as a base class without a lot of trouble? This kind of exercise can help you find flaws in your design early on as well as suggesting relationships and needs that you might otherwise miss.
I hope that you found this article useful in getting you started on discovering objects within your design. Let me know what you think or if you have any questions by leaving me a comment.
September 9th, 2007
When we start designing a user interface it should be obvious that we need to understand our users. Hopefully, formal requirements will provide some information but often that’s simply not enough. They may tell us things like what kind of computer, operating system, browser, or installed software a user has and they will describe what functions the program should have but rarely do they say anything about the user themselves. Let’s examine ways we can get to know our users and use that information to improve our programs.
Know Where the Users are Coming From
The first thing to remember is that users will tend to like whatever they’re using now. It could be a pen and paper form, an Excel spreadsheet or Access database with a little VBA code behind it, or something else that is no longer capable of doing the job effectively in the project sponsor’s opinion. They will typically be resistant to change unless the current method is very painful for them. Perhaps they will see their job as being threatened by a new program or business process. They often will resist learning anything new. They may even be unaware of the business trends that are driving the change. Also, they may not be aware of technological changes and prefer to do things in what they consider the old, reliable, way.
While some of this, such as changes to business processes, may fall on the project sponsors’ plate, as a user interface programmer you have to take this into account as well. You should avoid radical changes but, instead, go for evolutionary changes will move the users forward but not give them culture shock. For example, if you were moving an old Excel based VBA app to a web based solution you would probably want to maintain some of the spreadsheet style elements in your page designs. Or, if they used a paper form, mimic it somewhat in your design. The goal is to provide them with a new home they can become comfortable with quickly while meeting the functional requirements of the program.
Who are the Users?
In most circumstances you should be able to determine the profile of your typical users. Are they upper/middle managers? Phone operators? Sales agents? A wide range of users from across the company? What is their computer use skill level? What is their cultural and educational background? There are a lot of questions like this that you should ask that go beyond what is found in the average requirements document.
For UI design, you will want to particularly focus in on current computer knowledge since this can be a strong indicator of the approach you want to take. For example, if your program is for relative computer novices, a wizard-like step-by-step interface would probably be appropriate. But, if the program’s audience is primarily power-users, they might prefer a more direct hands-on approach. If it is for both user types, you may want to include both options. By understanding who they are, you can design the best interface options for them or at least develop a well considered compromise between the multiple user profiles.
Gathering this information can be tricky, particularly if you aren’t in the same location as the intended users. However, you should try to go directly to the source whenever possible rather than relying on what a project sponsor says about them. Often it can be quite different. I recommend arranging a team field trip to visit the facility where your users work if you can. It can be quite enlightening to see how the users currently do their job and to have them talk about what they like and dislike about their current methods. I would avoid paper surveys or intrusive methods like video taping. They just don’t seem to work as well from what I’ve observed.
Understanding The Users’ Tasks
Now that we know who the user is, we need to consider how they’ll go about their tasks. While we should have this in our functional requirements at a high level, we may still need more information. I’ve found it effective to rate the various tasks based on the following criteria:
- How often a particular task will be performed
- How critical the task is to the user’s work
- The amount of information needed to perform the task
- How many steps are required to perform the task now, if it is currently being performed
- Do the users need assistance or guidelines in performing the task
- What tools, other than the computer, are needed to perform the task (phone, barcode reader, etc.)
The goal is to design your interface so that this information is blended into it. For example, you want to make the common tasks easily identifiable to the users. They shouldn’t have to stumble about the interface and find a common task buried in a secondary dialog or two levels deep in a submenu. If the program is going to interface with an external device, such as a barcode reader, make sure your design makes this a smooth, perhaps even transparent, process, not a clumsy one. For uncommon or complex tasks you may want to provide some type of walk through assistance to help the users. The bottom line is that your UI should take into account how the users will do their work.
Understand the User’s Work Environment
Finally, we need to understand where the program will be used. Sometimes it may be used everywhere and anywhere. In that case, you want to design very generically and flexibly so that it isn’t tied to a single locale or user type. In other cases, the program may only be used by a specific group of people. Some of the things you want to consider are:
- What is their physical work environment? An Office? Store? Manufacturing facility?
- Are the users mobile, like traveling sales people, or fixed in a single location?
- What are the ergonomics of the situation? Will they be sitting or standing? How well will they be able to see and/or hear?
- Do some or all of the users have special needs such as multiple language support, accessibility support, and so forth?
Each environment type combination requires different approach. For example, a grid in a small font might work well for an executive in an office but it would be difficult for a manufacturing engineer to read across the room on a shop floor. Or a dull, business like, interface may be fine for an accounting app but you wouldn’t want to have an UI with no sizzle on a in-store customer relations program.
I hope this article has been helpful to you in designing and planning your user interfaces. Please let me know your ideas, thoughts and questions on user interface design by leaving a comment.
September 8th, 2007