Last night was spent reading a bit more about ADO.NET. There was a very good MSDN article, Best Practices for Using ADO.NET, that gives you an overview of how to use ADO.NET. It’s best to read it after getting some experience with ADO from another source.
I’ve also found a clear tutorial about threading in VB at dev-x, Add Multithreading to Your VB.NET Applications.
That tutorial doesn’t emphasize a pretty important fact about .NET threading: the Windows Forms controls are not thread safe. That means that you can’t mess with form controls from within a thread. A “solution” came to mind immediately: user defined events. That wasn’t quite enough, though.
The issue is basic: when an event is raised in a thread, the handler for that event executes within the same thread. Intuition would make you think otherwise. You think: if your control update function is in the form class, and you start a new thread with a different class, you tend to think that the event is raised by the new thread, and caught by the thread running the control. That’s not how it works. The handler code runs in the thread that raised the event.
It’s a can of worms, and it must be opened, and consumed. The best way to deal with it is to use the .NET 2.0 object, BackgroundWorker. See BackgroundWorker Class, and Walkthrough: Multithreading about writing generic background threads.
Events
There are also some more complex ways to deal with this, explained in the tutorials below. To comprehend what’s going on, I am reading these pages on msdn:
Events and Delegates, and Implement Events in Your Class
Safe Multithreading with the BackgroundWorker Component discusses that and explains a little about how to use delegates to protect the app.
MSDN also has the same info in Make Thread-Safe Calls to Windows Forms Controls
Anyway, I was hoping to make more headway on this issue today, but have opted to read more in depth about what’s really going on with the BackgroundWorker.
Delegates (some random notes)
MSDN has a good code sample in Delegate that is a little clearer than their description. A Delegate is a special class that is used to create Delegate objects. A Delegate object works like a C function pointer, or in JavaScript or other dynamic language, a function reference — that is, it’s a way to create an object that can call a function.
In a functional language like Scheme (or JavaScript, PHP, or Perl for that matter), regular variables can hold a reference to a function. A VB Delegate lets you do the same thing, but in a slightly more complicated way.
A constraint on delgates in .NET is that they are type safe — they have a type signature. So, if you create a delegate for a function that takes and Integer as an argument and returns an Integer as a value…
Delegate Function myMethodDelegate(myInt As Integer) As [Integer]
…it can create delegate objects only for functions that take an Integer arg and return an Integer.
...the definition... Public Function myIntMethod(myInt As Integer) As [Integer] ...can instantiate the delegate... Dim myD1 As New myMethodDelegate(AddressOf mySC.myIntMethod) ...and you use it... myD1(12)
Delegates in VB.NET discusses delegates in more depth, including topics not related to events.
Invoke
Here’s how to make a form thread-safe. First, you have to make a setter method of each form element that will be changed from another thread. For each setter, we do a little work to make sure the code runs in the form’s thread.
The form contains a method, InvokeRequired(), that determines if we’re in the form’s thread. If we’re not in that thread, we use the Invoke() method to make a method call within the form’s thread. Invoke takes a delegate as an argument. The delegate, as explained above, is a reference to a method.
Read this tutorial: WinForms UI Thread Invokes: An In-Depth Review of Invoke/BeginInvoke/InvokeRequred
See also: Plumbing the Depths of the ThreadAbortException Using Rotor
ADO.NET Reconsidered
After some contemplation, I am starting to understand the need for something like ADO.NET, because the networked environment increaingly exports data in different formats, and there’s going to be a need to do relational queries against this diverse, dynamic data. I’m more into the idea of a SQL-based, rather than C#/Java/VB-based query, though; maybe SQLite using a file in memory would work better for me. Unlike some programmers, I don’t have an aversion to SQL. It’s more concise and plain than procedural code. Even with it’s weird idioms.
It’s a matter of taste, I suppose. A lot of ASP.NET examples are busy hiding the SQL code way deep in classes, or piecing together SQL from bits of strings. I’m more into putting it all into one file or class, and making it as readable and inflexible as is practical. In fact, I’m inclined to expose the SQL as a way to communicate exactly what’s being shown. A programmer shouldn’t be more than a couple ctags-links from the SQL code that does the hard work.