0

I have been looking at the possible answers on various places on the Internet, and all don't seem to conform to my use case or are too vague for me to understand how to use them. Here is what I have come up with by looking at the top posts on Stack Overflow:

Delegate Sub delgation(text As String)
Public Sub SetToolText(text As String)
    If ToolStrip1.InvokeRequired Then
        Invoke(New delgation(AddressOf SetToolText), text)
    End If
End Sub

I don't understand how to use this in order to change my ToolStrip's TextLabel for two reasons:

  1. How exactly do you use this in another class?
  2. How do you know what item you are targetting in the ToolStrip? This is what has me the most confused. If I have two Labels, then which one am I setting text to? This is extremely confusing.

I intend to use it on my Downloader class:

Imports CefSharp
Public Class Download_Handler
    Implements IDownloadHandler

    Public Event Finished()
    Public Sub Before(Chromium As IWebBrowser, Browser As IBrowser, Item As DownloadItem, Callback As IBeforeDownloadCallback) Implements IDownloadHandler.OnBeforeDownload
        If Not Callback.IsDisposed Then Callback.Continue(IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Item.SuggestedFileName), True)
    End Sub

    Public Sub Updated(Chromium As IWebBrowser, Browser As IBrowser, Item As DownloadItem, Callback As IDownloadItemCallback) Implements IDownloadHandler.OnDownloadUpdated
        If Item.ReceivedBytes > 0 Then RaiseEvent Finished()
        main_window.SetToolText(String.Format("{0}/{1} bytes received", Item.ReceivedBytes.ToString, Item.TotalBytes.ToString))
    End Sub
End Class

Note this line: main_window.SetToolText(String.Format("{0}/{1} bytes received", Item.ReceivedBytes.ToString, Item.TotalBytes.ToString))

This on its own doesn't work, the text doesn't get set. I also tried to pass the label as a ToolStripLabel object when creating an instance for this class in order to reference it internally that way, but this causes the unsafe cross-threading error.

Thus I stumbled upon the endless samples of the aforementioned solution which makes little sense to me. How can I adapt it to my code?

(Edit) Someone asked for a reproducible sample:

  1. Create a WinForms .Net Framework Project
  2. Make sure your form is named as Form1
  3. Add the CefSharp Common and CefSharp WinForms Nuget Packages
  4. Add a ToolStrip named ToolStrip1
  5. Add a ToolStripLabel named DLProgressLabel within the ToolStrip
  6. Paste the below code and run:
Imports CefSharp
Imports CefSharp.WinForms
Public Class Form1
    Dim Cef As ChromiumWebBrowser
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Call InitCef()
    End Sub
    Private Sub InitCef()
        'Create Cef Settings
        Dim settings As New CefSettings()
        settings.CachePath = Application.ExecutablePath + "\BrowserData"
        settings.CefCommandLineArgs.Add("persist_session_cookies", "1")
        'Create Cef instance
        CefSharp.Cef.Initialize(settings)
        Cef = New ChromiumWebBrowser("https://download.mozilla.org/?product=firefox-latest-ssl&os=linux64&lang=en-GB") With {.Dock = DockStyle.Bottom}
        Cef.DownloadHandler = New Download_Handler()
        Me.Controls.Add(Cef)
    End Sub
    Delegate Sub delgation(text As String)
    Public Sub SetToolText(text As String)
        If Me.ToolStrip1.InvokeRequired Then
            Invoke(New delgation(AddressOf SetToolText), text)
        Else
            Me.DLProgressLabel.Text = text
        End If
    End Sub

End Class
Public Class Download_Handler
    Implements IDownloadHandler

    Public Event Finished()
    Public Sub Before(Chromium As IWebBrowser, Browser As IBrowser, Item As DownloadItem, Callback As IBeforeDownloadCallback) Implements IDownloadHandler.OnBeforeDownload
        If Not Callback.IsDisposed Then Callback.Continue(IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), Item.SuggestedFileName), True)
    End Sub

    Public Sub Updated(Chromium As IWebBrowser, Browser As IBrowser, Item As DownloadItem, Callback As IDownloadItemCallback) Implements IDownloadHandler.OnDownloadUpdated
        If Item.ReceivedBytes > 0 Then RaiseEvent Finished()
        Call Form1.SetToolText(String.Format("{0}/{1} bytes received", Item.ReceivedBytes.ToString, Item.TotalBytes.ToString))
    End Sub
End Class

As soon as it starts, it will begin downloading the Firefox file. Place a breakpoint on the Me.DLProgressLabel.Text = text part of the SetToolTip function and watch as it fails to change the text for no obvious reason.

Myronaz
  • 183
  • 1
  • 1
  • 10
  • What EXACTLY is `main_window`? Is it the type of your main form or is it a variable that refers to an instance of your main form? If it is the former then your code can't possibly work, even if you implement the method correctly as per the answer provided. – user18387401 Apr 17 '22 at 02:55
  • You should read [this](https://www.vbforums.com/showthread.php?498387-Accessing-Controls-from-Worker-Threads). It explains how to build up a working method of this type and how it actually works. – user18387401 Apr 17 '22 at 02:57
  • You should also not declare your own delegate. It doesn't necessarily hurt but it is pointless. If you want to invoke a `Sub` with no parameters then use the `MethodInvoker` delegate. If you want to invoke a `Sub` with parameters then use the appropriate generic `Action` delegate. If you want to invoke a `Function` then use the appropriate generic `Func` delegate. – user18387401 Apr 17 '22 at 02:59
  • https://stackoverflow.com/a/4699360/17034 – Hans Passant Apr 18 '22 at 12:50

1 Answers1

0

You're missing the other side of the If.

Try this:

Public Sub SetToolText(text As String)
    If ToolStrip1.InvokeRequired Then
        Invoke(New delgation(AddressOf SetToolText), text)
    Else
        ToolStrip1.Text = text
    End If
End Sub
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • It should also be `ToolStrip1.Invoke` rather than just `Invoke`. – user18387401 Apr 17 '22 at 03:41
  • `Invoke` would come off of the `Form` or user control, so it still works. It would be more consistent to use the same control, so I agree with you. – Enigmativity Apr 17 '22 at 04:12
  • True. I was thinking that it wouldn't work like that but, of course, it would. – user18387401 Apr 17 '22 at 04:46
  • This doesn't actually work. First of all, ToolStrip1 holds items, so setting its own text doesn't do anything. You have to target the items (a Label in my case). But even past that, If I call the Sub from my `Download_Handler` class which is its own file in the Project, it doesn't set the text, even though I can see in the debugger that the Invoke method works and the text I'm trying to set is there. But it doesn't set it. I'm not sure why. – Myronaz Apr 17 '22 at 12:12
  • @Myronaz - What would the `Else` part of the `If` to update the text that you wanted updated? – Enigmativity Apr 17 '22 at 23:03
  • I'm not 100% sure what you mean. If you mean what the else statement updates, it updates my a Label in my ToolStrip (`DLProgressLabel.Text`). If you mean what calls it, then that would be the `Download_Handler` class (see code in my original post). I also did more testing and noticed that it goes straight to Else, so nothing actually gets invoked. I'm guessing I'm calling the Sub in the wrong way? Again, check my original post for the way I'm doing it. – Myronaz Apr 17 '22 at 23:55
  • @Myronaz - You said `ToolStrip1.Text = text;` was incorrect. I'm asking you what would be correct? – Enigmativity Apr 18 '22 at 00:16
  • @Myronaz - If you're saying that it goes straight to the `Else` part then the call to `Updated` is already marshalling on to the UI thread. The issue would then be you're not updating the right thing or you've created two instances of your form and you're updating the wrong one. You need to show a [mcve]. – Enigmativity Apr 18 '22 at 00:18
  • I have added the sample you requested on the original post... and I think you may be right. I don't think I'm targeting the same instance of the UI form, but it isn't like I'm creating a new one anywhere... – Myronaz Apr 18 '22 at 12:38