0

I've got a winform named Form1.vb and a class named FZConsole.vb On the winform I've got a Richtextbox1 and I'm trying to append text to it from the class but it won't work.

From the Form1.vb I can easily do

Richtextbox1.AppendText("Console is currently ON.")

In the class I'm trying to do this, but it won't work:

Class FZConsole
Public Sub FZConsole()
    While True
            Form1.Richtextbox1.AppendText(Environment.NewLine & "Test From Class")

        Threading.Thread.Sleep(1)
    End While
End Sub
End Class
Randomizers
  • 71
  • 1
  • 1
  • 7
  • Where are you calling the sub `FZConsole`? – Chase Rocker Mar 19 '16 at 18:54
  • I'm calling it with a thread. `Dim thread_fzconsole As System.Threading.Thread = New System.Threading.Thread(AddressOf FZConsole.FZConsole)` – Randomizers Mar 19 '16 at 20:43
  • You should pass the Form or RichTextBox instance to your thread before you start it. **YOU ALSO** require to invoke the updating of the RTB, or else you'll be faced with a `CrossThreadOperation` exception. – Visual Vincent Mar 19 '16 at 21:15
  • Could you show me an example with some comments on it so I can learn easier? That would be great! I'm not that experienced in using threads. – Randomizers Mar 19 '16 at 21:24
  • These two answers of mine shows examples of invocation: [Answer 1](http://stackoverflow.com/a/35782000/3740093), [Answer 2](http://stackoverflow.com/a/35993139/3740093) – Visual Vincent Mar 19 '16 at 21:54
  • This is also a good article to read: https://msdn.microsoft.com/en-us/library/ms171728(v=vs.110).aspx – Visual Vincent Mar 19 '16 at 22:01
  • I have now added an answer which explains invocation more thoroughly. – Visual Vincent Mar 19 '16 at 23:01

2 Answers2

0

When accessing controls from another thread you must typically invoke the accessing/updating of the control. This is done to synchronize the updating of the controls, so that two threads does not update one control at the same time.

You can think of it like this: two people cannot write at the same paper at the same time.

Invocation is usually nothing hard. It's basically just doing these two things:

  1. Check if invocation is required by the control or it's container.
  2. Invoke if necessary.

Invocation is performed using Delegate methods. If you target .NET Framework 4.0 or higher you can use the Sub() lambda expression to create a very simple delegate.

Public Sub FZConsole()
    While True
        If Form1.InvokeRequired = True Then 'Invocation is required.'
            Form1.Invoke(Sub() Form1.Richtextbox1.AppendText(Environment.NewLine & "Test From Class"))
        Else 'Invocation is not required.'
            Form1.Richtextbox1.AppendText(Environment.NewLine & "Test From Class")
        End If

        Threading.Thread.Sleep(1)
    End While
End Sub

However if you target .NET Framework 3.5 or lower things become a little trickier. When targeting an earlier framework you have to declare the delegate yourself, and it's not as simple as using the lambda since it works differently when passing variables.

Delegate Sub TextUpdaterDelegate(ByVal Text As String)

Public Sub FZConsole()
    While True
        If Form1.InvokeRequired = True Then 'Invocation is required.'
            Form1.Invoke(New TextUpdaterDelegate(AddressOf RichTextBox1.AppendText), Environment.NewLine & "Test From Class")
        Else 'Invocation is not required.'
            Form1.Richtextbox1.AppendText(Environment.NewLine & "Test From Class")
        End If

        Threading.Thread.Sleep(1)
    End While
End Sub
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
  • @Randomizers : Please remember to mark as answer if I solved your problem. :) – Visual Vincent Mar 20 '16 at 17:37
  • It says InvokeRequired is not declared for FZConsole, I tried to create a class inside main but that wouldn't work it didn't append text so :/ – Randomizers Mar 22 '16 at 11:35
  • @Randomizers : Right, sorry. I used `Me` in a form context. So replace every `Me` with for example `Form1` instead (note that you must target the form that you're going to update). I edited my answer to correct that. – Visual Vincent Mar 22 '16 at 16:46
  • `InvokeRequired` is a property of forms and controls. It's used to know wether you need to invoke _(simple enough)_. Try my edit and it should work. – Visual Vincent Mar 22 '16 at 16:51
  • It's still not appendingtext to the textbox. Here is how I start the thread. `Dim thread_fzconsole As System.Threading.Thread = New System.Threading.Thread(AddressOf FZConsole.FZ2Console)` – Randomizers Mar 24 '16 at 18:04
  • @Randomizers : Could you perhaps e-mail me your code? You will find my mail if you go into my Stack Overflow profile, then to my website, and into the "Support" section. **--- By the way** skip the `=`, it's shorter: `Dim thread_fzconsole As New Threading.Thread(AddressOf FZConsole.FZ2Console)`. – Visual Vincent Mar 24 '16 at 18:15
  • Send email with project files and everything explained in the email. thanks! – Randomizers Mar 24 '16 at 18:50
  • @Randomizers : Will you do that, or are you telling me to? – Visual Vincent Mar 24 '16 at 18:53
  • I meant that I sent an email! :) – Randomizers Mar 24 '16 at 19:25
  • @Randomizers : Just to notify you, I haven't got one yet... So if you've sent it you might check that you sent it to the correct address. – Visual Vincent Mar 24 '16 at 21:19
  • What's your mailadress? I sent it to the one on your website – Randomizers Mar 24 '16 at 21:35
  • @Randomizers : It's the one in the support section. Are you sure you've spelt it correctly? Has the mail gone away? Try copy-pasting it, I cannot share it on Stack Overflow because the moderators doesn't allow that. _Is there any way I can find yours?_ --- **Also, don't include the `mailto:` part!** – Visual Vincent Mar 24 '16 at 21:36
  • If your attachment is too big you cannot send it either (I think limits go somewhere between 2-16 MB). – Visual Vincent Mar 24 '16 at 21:47
-1
Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim newInstanceToClass As New SomeClass
        RichTextBox1.AppendText(newInstanceToClass.returenText)
    End Sub


    Class SomeClass
        Function returenText() As String
            Dim txt As String = "some text..."
            Return txt
        End Function
    End Class
End Class
Jonathan Applebaum
  • 5,738
  • 4
  • 33
  • 52
  • What if I want to send other and not only string? Like ("Total players: " + pPlayers) – Randomizers Mar 19 '16 at 20:42
  • so write another function that returnees integer. its very basic stuff you need to read about the basics of programming languages (functions and returnuing types OOP etc..). if thats the answer please mark it as an answer. – Jonathan Applebaum Mar 19 '16 at 20:54
  • Please include some kind of explanation in your answers and not just code. What does this do, and why should he use it? – Visual Vincent Mar 19 '16 at 21:12
  • Check, I posted an answer where I've done as you said but it still wont work for some reason. – Randomizers Mar 23 '16 at 14:29