Results 1 to 1 of 1

Thread: VB.Net tips and tricks you might be interested in.

  1. #1

    Thread Starter
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    8,598

    VB.Net tips and tricks you might be interested in.

    I just wanted to share some small tips and tricks I've personally been using as of late in VB.Net that makes life just a little bit easier for certain things. These are not big or revolutionary in any way. Just some very minor things that I arrived at as a natural progression of continual use of VB.Net.

    Make any function asynchronous.
    Code:
    Public Class Form1
    
        Private Function TakeLongTimeToDoSomething(ByVal x As Integer) As Double
    
            Dim d As Double = CInt(x)
    
            For i = 1 To 10
                d = d / 9
                Threading.Thread.Sleep(500)
            Next
    
            Return d
        End Function
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Me.Text = TakeLongTimeToDoSomething(5000)
        End Sub
    End Class
    Look at the above code. You press a button and it executes some long running task after which it returns a value. The problem with the above is that it locks up the UI while it's performing the task. Now your first instinct might be to use multi-threading. You might do something like this:-
    Code:
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Threading.ThreadPool.QueueUserWorkItem(Sub()
                                                       Dim value = TakeLongTimeToDoSomething(5000)
    
                                                       Me.BeginInvoke(Sub()
                                                                          Me.Text = value.ToString
                                                                      End Sub)
    
                                                   End Sub)
    
    
        End Sub
    Now the above works but it's a little wordy, don't you think? You also have an additional problem in that the button could now be pressed multiple times before the first one completes. You might think to yourself that you could disable the button during the time the work is being done:-
    Code:
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Button1.Enabled = False
    
            Threading.ThreadPool.QueueUserWorkItem(Sub()
                                                       Dim value = TakeLongTimeToDoSomething(5000)
    
                                                       Me.BeginInvoke(Sub()
                                                                          Me.Text = value.ToString
                                                                          Button1.Enabled = True
                                                                      End Sub)
    
                                                   End Sub)
    
    
        End Sub
    This works but look at the structure. That is ugly. Firstly it's a lot of boilerplate and now with the disabling and enabling of the buttons you have related things spread between the event handler and the worker thread. That is very difficult to follow and if it gets more complicated, it would become error prone.

    So how can we simplify all this? Well you could use a combination of Tasks and Async/Await. All of that could be simplified to this:-
    Code:
        Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Button1.Enabled = False
    
            Me.Text = Await Task.Run(Function() TakeLongTimeToDoSomething(5000).ToString)
    
            Button1.Enabled = True
    
        End Sub
    Doesn't that look a lot more manageable and easy to understand?

    Perform complex initialization of variables

    We are all familiar with variable initialization:-
    Code:
    Public Class Form2
        Private _fib = {0, 1, 1, 2, 3, 5, 8, 13}
    End Class
    The above code initializes an array variable with the Fibonacci sequence. Simple right? But what if we wanted to initialize it with a calculation instead. We could do this:-
    Code:
    Public Class Form2
        Private _fib As Integer()
    
        Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim a = 0I, b = 1I, c = 0I
            Dim l As New List(Of Integer)
            l.AddRange({a, b})
    
            For i = 2 To 7
                c = a + b
                l.Add(c)
    
                a = b
                b = c
            Next
    
            _fib = l.ToArray
    
        End Sub
    End Class
    Perfectly reasonable. But now we have separated the initialization from the declaration. What if you started adding more functions to that class and pushed Form2_Load to somewhere in the middle or bottom? Every time you wanted to know how that array was initialized you'd have to wade through a bunch of code to find Form2_Load and to make matters worse, what if you decided to put all initialization into a function that is called by the Load event? That is another level of indirection you'd have to trace. Wouldn't it be nice if we could perform this initialization where it was declared to keep everything more organized? Well you can do this by clever use of an anonymous function. You could do this:-
    Code:
    Public Class Form2
        Private _fib As Integer() = (Function()
                                         Dim a = 0I, b = 1I, c = 0I
                                         Dim l As New List(Of Integer)
                                         l.AddRange({a, b})
    
                                         For i = 2 To 7
                                             c = a + b
                                             l.Add(c)
    
                                             a = b
                                             b = c
                                         Next
    
                                         Return l.ToArray
                                     End Function).Invoke()
    End Class
    Now the initialization and the declaration of the array are one unit. This one looks a bit ugly due to how much code there is to calculate a Fibonacci sequence but in practice it won't always be this verbose. You'd mostly use it to set properties on classes where the class constructor doesn't provide adequate means to do so. Here's an actual example from a working program:-
    Code:
        Private client As HttpClient = (Function()
                                            Dim c As New HttpClient
    
                                            c.DefaultRequestHeaders.UserAgent.Add(New Headers.ProductInfoHeaderValue("NiyaScaper", "1.0"))
    
                                            Return c
                                        End Function).Invoke
    Tracking progress of a function

    This one is my favorite. Let's say you have a function like a file download where you need to track the progress. Look at this:-
    Code:
    Public Class Form3
        Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Button1.Enabled = False
    
            Await Task.Run(Sub() DownloadFile())
    
            MessageBox.Show("Download complete!")
    
            Button1.Enabled = True
        End Sub
    
        Private Sub DownloadFile()
            Dim r As New Random
    
            For i = 1 To 100
                Threading.Thread.Sleep(r.Next(100, 300))
            Next
    
        End Sub
    
    End Class
    The above is a mock-up of a downloader. You click the Button and it starts an asynchronous download. When the download is finished, we are informed through a message box. But what if we wanted to track the progress of the download? We might do this:-
    Code:
        Private Sub DownloadFile()
            Dim r As New Random
    
            For i = 1 To 100
    
                Me.Invoke(Sub()
                              ProgressBar1.Value = i
                          End Sub)
    
                Threading.Thread.Sleep(r.Next(100, 300))
            Next
    
        End Sub
    We changed our DownloadFile function to report progress to a ProgressBar. This is actually very bad because we have now married our download function to the UI itself. If we wanted to take that function and dump it into it's own class or use it in another project, we must now untangle it from the UI. Good news is, we can unmarry this function from the UI through the use of delegates:-
    Code:
    Public Class Form3
        Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Button1.Enabled = False
    
            Await Task.Run(Sub() DownloadFile(Sub(i As Integer)
                                                  Me.Invoke(Sub()
                                                                Me.ProgressBar1.Value = i
                                                            End Sub)
                                              End Sub))
    
            MessageBox.Show("Download complete!")
    
            Button1.Enabled = True
        End Sub
    
        Private Sub DownloadFile(Optional ByVal reportProgress As Action(Of Integer) = Nothing)
            Dim r As New Random
    
            For i = 1 To 100
                If reportProgress IsNot Nothing Then reportProgress.Invoke(i)
    
                Threading.Thread.Sleep(r.Next(100, 300))
            Next
    
        End Sub
    
    End Class
    Now DownloadFile is capable of reporting progress without being married to the UI. You can now freely move that function to wherever you like. The UI code will take responsibility for updating the progress bar as it should. DownloadFile should not even know that a UI exists.

    Anyways, that's all I have for today. Have a good day everyone.
    Last edited by Niya; Jun 18th, 2022 at 02:46 PM.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width