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.
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:
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)
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.
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.
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.