[vb.net] How to organize a long procedure RRS feed

  • Question

  • I'm having inside a textbox textchanged event a long procedure and I'd like to make it easier and lighter. So, I'm trying to check what clipboard has and if it respect some parameters, it can goes forward. I want basically to create a step by step thing. So, I'm trying to clean the code:

     If (My.Settings.Dfolder = "") Then
            Label2.Text = "Download folder is missing "
            If Clipboard.GetText.Contains("youtube") = False Then
                Label2.Text = "It doesn't contain a youtube link "
                If TextBox1.Text = Clipboard.GetText Then
                        Label2.Text = "You are trying to use the same link"
                        TextBox1.Text = Clipboard.GetText
                    End If
                End If
            End If
        End If

    So, this for me it works perfectly, as it makes it step by step and it doesn't go forward if the first if statement is not respected. The problem is when I want to go forward.
    After "TextBox1.Text = Clipboard.GetText" the program have to do following things:

    1. Get documenttitle of youtube link(downloading it with webclient.downloadstring and Regular expression to get page title.

    2. Check if title doesn't contain invali filename chars

    3. Check with that title, if the file exist in C:\ or download path

    4. If file doesn't exist then the webbrowser(luckly is the only one ..) will start navigate to a page where the document completed will get the "download link" (I'm downloading songs from an already existing platform) and it is using that link in order to create a QR Code by google api which will give me back the qr image.

    5. Add to a richtextbox the title name as it has been downloaded.

    6. then I'm adding the title name to an online notepad by a POST request(I know it is not professional, but I like it as it's working properly and also easier than create(and pay) a database )

    7. I'm displaying this notepad in a listbox(Betterlistbox1)

    8. if the file exist(point #4) then It will just show to user where the file is located.

    I have already coded all this but I'm using almost all of it inside a textbox textchanged event, Which is completely a mess. For example, if the connection is a bit slow or it misses signal for a second it will mess up all this procedure as it's working just if everything goes smoothly with fine connection. Also, the download is done with the link extracted from webbrowser, but I have to make a "oh my god" procedure. I'm filling a secondary textbox (different from the one for the main link) with the download link and the textchanged event is starting the async download. It is basically a very fragile procedure, as If something doesn't work properly, or the webbrowser doesn't load in a reasonable time, it will create delays , and delays here means not being able to make the next step. For example, after a while I realize that sometimes it stays the previous titlename, downloading song X as SongY, becuase the title extraction took a bit more than "normal". My question is: How can I organize everything step by step? Everything should start from beginning to end with logic. If the webbrowser is taking a bit more to load than all the process must be "aware" of the situation. Something like if webbrowser take 1 hour to grab the download link, then suddenly the next step is suddenly ready and working. I visualize this as a 7 × 100 metres relay. The code I wrote is:

                'Under main textbox textchanged event
                    Dim x As New WebClient()
                    x.Encoding = Encoding.UTF8
                    Dim source As String = x.DownloadString(TextBox1.Text.Replace(" - YouTube", ""))
                    Dim title As String = Regex.Match(source, "\<title\b[^>]*\>\s*(?<Title>[\s\S]*?)\</title\>", RegexOptions.IgnoreCase).Groups("Title").Value
                    Dim a As String = title.Replace(" - YouTube", "")
                    Dim webdecode As String = WebUtility.HtmlDecode(a)
                    Label13.Text = String.Join("-", webdecode.Split(IO.Path.GetInvalidFileNameChars))
                    Label2.Text = "Getting title "
                    Label2.ForeColor = Color.ForestGreen
                    Dim folderPatha = TextBox4.Text
                    Dim filePatha = Directory.GetFiles(folderPatha,
                                              Label13.Text + ".mp3",
                    If filePatha Is Nothing Then
                        WebBrowser1.Navigate("Download website" + TextBox1.Text.Replace("https://www.youtube.com/watch?v=", ""))
                        If RichTextBox1.Text.Contains(Label13.Text) = False Then
                            'ADD TITLE TO RTB1 
                            RichTextBox1.AppendText(vbLf + Label13.Text + Environment.NewLine)
                  'extract the content of betterlistbox and  update the notepad online with this last title
                            Dim hey As String = (String.Join(vbLf, BetterListBox1.Items.Cast(Of String)) + vbLf + "Inga - " + Label13.Text + vbLf)
                            Dim ok As Boolean = SaveData(hey, "011hk762", "63958th7q")
                        End If
                            Dim risposta As String
                            risposta = MsgBox("File existing in " + vbLf + textbox4.text + "\" + Label13.Text + ".mp3" + vbLf + "Would you like to open the folder?", vbYesNo)
                            If risposta = vbYes Then
                                Process.Start("explorer.exe", "/select," & filePatha)
                            End If
                        End If
                    End If
            Catch ex As Exception
            End Try

    While the timer that is updating BetterListbox from (online notepad) is:

    Private Async Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Dim task1 As Task = Task.Run(Sub()
                                                 Dim res As String
                                                 Dim client As WebClient = New WebClient()
                                                 client.Encoding = Encoding.UTF8
                                                 client.Headers.Add(HttpRequestHeader.UserAgent, "")
                                                 Dim stream = client.OpenRead("notepadonlinelink")
                                                 Dim sr As StreamReader = New StreamReader(stream)
                                                 res = (sr.ReadToEnd)
                                                 'FILTER HTML TAGS
                                                 Dim sourcestring As String = res
                                                 Dim matchpattern As String = "<(?:[^>=]|='[^']*'|=""[^""]*""|=[^'""][^\s>]*)*>"
                                                 Dim replacementstring As String = ""
                                                 res = ((Regex.Replace(sourcestring, matchpattern, replacementstring)))
                                                 Dim clientdecode As String = WebUtility.HtmlDecode(res)
                                                 Label15.Text = clientdecode
                                             Catch ex As Exception
                                             End Try
                                                               Dim visibleItems As Integer = BetterListBox1.ClientSize.Height / BetterListBox1.ItemHeight
                                                               'I add the value of notepad online in betterlistbox                                                           
                                                               BetterListBox1.Items.AddRange(Split(Label15.Text, vbLf))
                                                               BetterListBox1.TopIndex = Math.Max(BetterListBox1.Items.Count - visibleItems + 1, 0)
                                                           End Sub)
                                             Catch ex As Exception
                                             End Try
                                         End Sub)
            Await task1
        End Sub

    While the webbrowser document completed event got:

                'extracting download link
                Dim collection As HtmlElementCollection = WebBrowser1.Document.All
                For Each element As HtmlElement In collection
                    If element.TagName = "A" Then
                        Dim link As String = element.GetAttribute("HREF")
                        If link.Length > 70 Then
                            link = link.ToString.Replace(" - YouTube", "")
                            TextBox3.Text = link
                        End If
                    End If
                'and I'm gonna use it to create a qrcode
                Dim sitoGoogleQrCode As String = "http://chart.googleapis.com/chart?chs={WIDTH}x{HEIGHT}&cht=qr&chl={TESTO}"
                sitoGoogleQrCode = sitoGoogleQrCode.Replace("{WIDTH}", PictureBox1.Width.ToString()).Replace("{HEIGHT}", PictureBox1.Height.ToString()).Replace("{TESTO}", WebUtility.UrlEncode(TextBox3.Text))
                Dim client As WebClient = New WebClient()
                Dim bytes As Byte() = client.DownloadData(sitoGoogleQrCode)
                Dim memStream As MemoryStream = New MemoryStream(bytes)
                Dim bmpQrCode As Bitmap = New Bitmap(memStream)
                PictureBox1.Image = bmpQrCode
            Catch ex As Exception
            End Try

    And in another textbox textchanged event:

     Dim Path As String = TextBox4.Text
            Dim filepath As String = (Path + "\" + Label13.Text + ".mp3")
            mclient.Encoding = Encoding.UTF8
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
            mclient.Headers.Add(HttpRequestHeader.UserAgent, "")
            mclient.DownloadFileAsync(New Uri(TextBox3.Text), filepath)

    Thanks if you kept reading until here. I want to say that I know I'm making mess declaring variables many times as I cannot access the object. The code needs to be really clean, but for the moment, how can I organize all this? Do I need to split the things and add them in classes and call them whenever I need ?

    Many thanks

    • Edited by Mattia Fanti Saturday, October 10, 2020 12:00 AM
    Friday, October 9, 2020 10:43 PM

All replies

  • Hello,

    Rather than run through how to provide a response to the current code how about a different train of thought.

    The very first thing to do is separate user interface from code logic. This means to have a class split up into task (functions and procedures) were communication goes to the user interface using delegates and events (the average developer tends to avoid, never learn about delegates and events). Couple this with moving away (for the most part) Timer components in favor of asynchronous task based style of coding. When gluing pieces back and forth between back end classes and your form, give control names better names then default names, even labels if setting their Text property at run time.  

    A very basic code sample which goes with the above, in this case updates a Progressbar but can be any type of control from label to DataGridView and any control in between. In the same solution the basic code sample is in is an extension method I use in C# and wrote a VB.NET version for performing invoke in asynchronous task based operations in tangent with delegates and events.

    Another thing to assist with decoupling front end from backend and even backend from backend is to learn how to use namespaces and also aliases for import statements. Both namespaces and import alias are demonstrated in the following project where I have FileOperations in the same project under different namespaces. 

    In closing I have not provided an answer to the current question but instead gave you alternate (and how professional developers) to consider.

    See also: Delegates (and note I go deeper in my first code sample and attempt to make it easy to understand)

    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    profile for Karen Payne on Stack Exchange

    Saturday, October 10, 2020 12:34 AM