Archive for category Programming
In my company’s offices, we have been using the Microsoft Interop Forms Toolkit to integrate new UI content with a legacy UI that isn’t going away any time soon. The toolkit includes an add-in that generates interop-friendly code for the forms and controls that are in the project.
The toolkit was last updated when Visual Studio 2010 was the current release. Since then, we have moved on to VS2012, VS2013, and VS2015. The majority of the toolkit works great in Visual Studio 2015. The exception is the add-in. Add-ins are not supported at all in Visual Studio 2015. We have been managing this by opening the project in Visual Studio 2010 to generate code via the add-in.
Updated technical requirements have forced us to update our projects to target .NET Framework 4.5. Unfortunately, this makes the projects incompatible with Visual Studio 2010. I searched for solutions on the Internet, but could not find anybody who had published any alternatives. I did find plenty of other people requesting support for new versions of Visual Studio.
With my company’s support, the add-in source code from the original toolkit has been converted to a Visual Studio Extensibility solution. The source code for this port is publicly available.
At work, we’re heavily invested in the Interop Forms Toolkit while our product is slowly being migrated from VB6 to .NET.
When you are creating a .NET control to be hosted on a VB6 form, there are several limitations mentioned in the documentation, including:
You should not show a .NET form from an Interop UserControl. The .NET form will not close if the parent form is closed first, and tabbing on the .NET form will not work.
This was going to be a problem for us. Our product has lookup text boxes that launch a search dialog when the user leaves the field with a partial or ambiguous value. The search dialog is a .NET form, so we were concerned that this was going to cause problems.
We tried it anyway. Our interop user controls are always composite controls that can include multiple lookup text boxes. We figured that maybe things would be a little different because we were showing the form modally from within a contained control.
We found that it worked, mostly. The big stickler was when a highly productive worker was entering data using the keyboard. The TAB key would launch the search dialog, but then the focus got stuck somewhere that would not respond to the keyboard any more. They had to use the mouse to get focus back on the form, which was disruptive to their flow.
Other workflow scenarios, such as explicitly launching the search dialog with a function key (i.e. not tabbing) were working just fine and not losing focus.
I won’t rehash all the details of the debugging effort. We added lots of debug statements to event handlers and overrides of methods that were related to key input and focus. We were able to identify this sequence of events that was relevant:
- “Entered” event on the constituent lookup control.
- “ProcessTabKey” method on the host user control.
- “Leave” event on the constituent lookup control.
- “Leave” event on the host user control.
- Search dialog is displayed…
- “Validating” event on the constituent lookup control.
- “Validated” event on the constituent lookup control.
#Region " Custom search focus handling " ' When this control is hosted on a VB6 form using interop, tabbing out of a field that ' launches a custom search dialog causes focus to leave the control and the user ' can no longer navigate with the keyboard unless they use the mouse to put focus ' back into the control. This block of code detects the scenario and sets focus to the ' appropriate control. ' Two textboxes on the new item use custom search: ' Lookup1 ' Lookup2 ' The following sequence of events leads to the problem. These events can also ' occur in other scenarios, but they will not occur in this exact sequence. ' Lookup control is entered ' Tab key is pressed (ProcessTabKey) ' Custom search dialog makes this control lose focus (OnLeave) ' The fix will set focus back to the appropriate field after the dialog ' returns. This will happen when the control is validated, but only when ' the appropriate sequence of events has occurred. A state machine enum ' is used to manage this. Private Enum CustomSearchFieldState Null Editing Tabbing NeedsFocus End Enum Dim mCustomSearchFieldState As CustomSearchFieldState = CustomSearchFieldState.Null Dim mCustomSearchField As MyCustomLookupTextBox Dim mCustomSearchFieldTabForward As Boolean = False Private Sub CustomSearchEnter(sender As Object, e As System.EventArgs) _ Handles Lookup1.Enter, Lookup2.Enter ' The problem only occurs when the control is hosted in VB6. We can detect that specific ' scenario through the ParentForm property. In .NET, we will have a parent form. In VB6, ' the parent form is null. If Me.ParentForm Is Nothing AndAlso mCustomSearchFieldState = CustomSearchFieldState.Null Then mCustomSearchField = DirectCast(sender, MyCustomLookupTextBox) mCustomSearchFieldState = CustomSearchFieldState.Editing End If End Sub Protected Overrides Function ProcessTabKey(forward As Boolean) As Boolean If mCustomSearchFieldState = CustomSearchFieldState.NeedsFocus Then ' This state indicates that the user canceled out of a previous custom ' search. They may have chosen to change direction, so we update ' the direction flag. mCustomSearchFieldTabForward = forward End If If mCustomSearchFieldState = CustomSearchFieldState.Editing Then mCustomSearchFieldState = CustomSearchFieldState.Tabbing mCustomSearchFieldTabForward = forward End If Return MyBase.ProcessTabKey(forward) End Function Protected Overrides Sub OnLeave(e As System.EventArgs) If mCustomSearchFieldState = CustomSearchFieldState.Tabbing Then mCustomSearchFieldState = CustomSearchFieldState.NeedsFocus End If MyBase.OnLeave(e) End Sub Private Sub CustomSearchValidated(sender As Object, e As System.EventArgs) _ Handles Lookup1.Validated, Lookup2.Validated If mCustomSearchFieldState = CustomSearchFieldState.NeedsFocus Then Me.Focus() Me.SelectNextControl(mCustomSearchField, mCustomSearchFieldTabForward, True, True, True) End If ' Validation is the final event in all states and resets the custom search workaroud. mCustomSearchFieldState = CustomSearchFieldState.Null mCustomSearchField = Nothing End Sub #End Region
From an interview with Niklaus Wirth (added emphasis is mine):
- ‟Do you think better education is the answer to poor software? Surely teaching people better would be cheaper in the long run and certainly avoid the huge bloat we see today and we would be able to use simpler and less power-hungry hardware?”
- ‟A proper education certainly would help. However, the belief is wide-spread that programming is easy, can be learned on the job, and does not require specific training or talent. However, it is not programming in the sense of coding that is the problem, but design. Applications have become very demanding and their tasks complex. Mastering this growing complexity is the primary challenge. To tackle this task requires experience and an explicit ability for abstraction on many levels. It is difficult to learn this, and even more so to teach it. Not every programmer is a born designer.”
All I can say to this is “Amen, Brother!” I have worked side-by-side with a number of developers over the years, and I consider this statement to be an absolute truth.
I also believe that programmers who have a natural ability to easily context-switch between details and abstract concepts fall into the category of programmers who are an order of magnitude more productive than many of their peers.
I think algebra is a good precursor to identifying programming potential. Prior to algebra, math education in the United States focuses on the mechanics. Success in algebra requires an ability to take abstract problems (i.e. word/story problems) and translate them into concrete details.
In school, I tutored a handful of friends and classmates who were taking algebra. Some just needed a different viewpoint to grasp the concept they were struggling with. Others, however, just did not get the concepts, and I believe their brains are simply not wired to think that way. These were not stupid people! They had talents in other areas that just didn’t fit into the abstract concepts of algebra.
I’ve begun studying to take the 70-536 exam. I read about Nullable types in my study material and decided to review MSDN’s topic on the subject. The documentation includes a complicated truth table regarding tri-state boolean logic.
Here’s how I think of it, without having to worry about looking up the value in a large truth table.
- True: Both operators are true
- False: Either operator is false
- Nothing/Null: Any other combination.
- True: Either operator is true
- False: Both operators are false
- Nothing/Null: Any other combination.
I wonder how common it is to add an extra syllable, like saying “nu-ku-ler” instead of “nu-clear”?
I recently ran across this older post about Nine Things Developers Want More Than Money. I can relate to items 3, 4, 5, 7, 8, and 9. I’m fortunate to have most of those things in my work environment, except for #9. I’m working on a project that interfaces new work in VB.NET with existing work that was done in VB6 several years ago. I wrote most of the code on both ends, and I curse myself at least once a week for being so ignorant when I wrote the VB6 code several years ago. 🙂
I recently ran across Kate Gregory’s post on tracepoints. She’s a C# person, but this technique works in Visual Basic.NET, too.
I did have a problem getting the results to print in my Debug window, as Kate shows on her post. VB.NET has an option to send Debugging information to the Immediate Window, rather than to the Output window. Until I knew this, I was looking for the information in the wrong place.
To change this behavior, select Tools -> Options from the menu. Make sure “Show all settings is checked”. The Debugging/General node has an option, “Redirect all Output Window text to the Immediate Window.” I have turned this option off, as I never use the Immediate Window in VB.NET.