Keskustelut - Visual Basic / C# / .NET - VB .NET 2010 Miten saan threadille palautettua formin objekteilta (TextBox) tietoa?


Kili 17:39 15.3.12 
Listener Luokka jonka sisällä seuraavaa:

Public Sub Main()
'Starttaa treadin form loadista tai nyt tällä hetkellä napilta formilta.

ListenerThread = New Thread(AddressOf Listen)
ListenerThread.Start()

End Sub

Public Sub Listen()

'Public Shared Sub main()

Dim server As TcpListener
server = Nothing
Try
' Set the TcpListener port


Dim port As Int32 = CInt(GetServerPort()) 'Funktio toimii mutta palauttaa aina defaultiksi kirjoitetun "PORT" sanan vaikka threadin käynnistäisi vasta napilla kun kaikki formiin liittyvä on ladattu.
Dim ServerAddr As IPAddress = IPAddress.Parse(form.ServerIP_TB.Text) 'Tämä rivi ei toimi suoraan thread luokan sisältä

server = New TcpListener(ServerAddr, port)

' Start listening for client requests.
server.Start()
.............................
............................


Private Delegate Function ServerPORTInvoker() As String
Private Function GetServerPort() As String
Dim text As String
If form.ServerPort_TB.InvokeRequired Then
text = CStr(form.ServerPort_TB.Invoke(New ServerPORTInvoker(AddressOf GetServerPort)))
Else
text = form.ServerPort_TB.Text
End If
Return text
End Function


Elikkä ilmeisesti tuossa delegate tai invoke systeemissä menee jotain pieleen?
Kellään sattuisi olemaan yksinkertaista mallia miten saan formilta objekteista (TextBox) haettua tietoja tuon kuuntelia threadin tarpeiksi???
Ja seuraavaksi sitten pitäisi vielä saada kirjoitettua formille logia richtextboxiin
weicco 20:25 15.3.12 
Siis nappi käynnistää threadin ja threadi kysyy textboxista arvon? Älä herranen aika tee noin. Tuossa on valtava race condition. Syötä sen sijaan textboxin arvo parametrina threadille. Ks. MSDN:stä lisätietoja.

http://msdn.microsoft.com/en-us/library/1h2f2459(v=vs.110).aspx
editoitu: 23:24 15.3.12
Jari_Kettunen 23:20 15.3.12 
Miksi homma täytyy tehdä threadin kautta. Onko kyseessä joku valvomosofta jossa käppyrät päiviittyvät taustalla lennosta itsenäisesti. Vai joku koulutehtävä jossa pitää käyttää threadeja. Ensin haltuun button_click johon koko homma sisään synkronisesti.

ps. kotisivusi linkki ei toimi.
Kili 08:22 16.3.12 
Kyseessä on pieni socket palikka, jonka tarkoitus on ottaa viestejä vastaan ja lähettää TCP/IP:n kautta. Työ aisiahan tämä on ja tarkoitus laittaa käynnistymään tuo kuuntelija formin onloadista. Käsittääkseni net.sockets kuuntelija ilman threadia keskeyttää muun sovelluksen toiminnan? Ei ole vuosiin tarvinnut Visual Basic .net ohjelmointiin koskea joten siksi aika lailla ulalla. Kotisivu ei varmaan ole toiminut aikoihin kun koulukin on käyty jo ajat sitten.
Kiitokset Weicolle, kokeilen tuota parametrisointia seuraavaksi.
Kili 10:07 16.3.12 
Mitenkäs tuolta threadin sisältä pystyy järkevästi lisäämään rivejä formilla olevaan RichTextBoxiin?
editoitu: 10:33 16.3.12
Jari_Kettunen 10:32 16.3.12 
Seuraavassa Microsoftin koodista käy selväksi miten homman voi tehdä.
http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx#Y400
Kili 12:19 16.3.12 
Löysin tuon saman ohjeen ja olen sen mukaisesti yrittänyt palautella tietoa richtextboxille mutta en saa sinne tulemaan rivejä.
Pitäisikö tuo threadi käynnistää form luokan puolelta? Tällä hetkellä formin button kutsuu kuuntelija luokkaa jossa startataan threadi ja aletaan tehdä juttuja.

Tällä hetkellä:

Public class TcpListenerClass
Delegate Sub SetTextCallback([text] As String)

Public Sub Main()
Dim Params(1) As Object

Params(0) = form.ServerIP_TB.Text
Params(1) = form.ServerPort_TB.Text

Dim ListenerThread As New Thread(AddressOf Listen)
ListenerThread.Start(Params)

End Sub

Public Shared Sub ADDLineToSVRLOG(ByVal str As String)
If form.Server_RTB.InvokeRequired Then
form.Server_RTB.Invoke(New Server_RTBDelegate(AddressOf ADDLineToSVRLOG), str)
Else
form.Server_RTB.AppendText(str & vbNewLine) 'Menee else haaran kautta
End If
End Sub

Public Shared Sub Listen(ByVal Params As Object)

ADDLineToSVRLOG("TEST2") 'Kutsu menee läpi ilman virheitä mutta mitään ei ilmesty formin richtext boxiin???

Dim server As TcpListener
server = Nothing
Try
' Set the TcpListener port

Dim port As Int32 = CInt(Params(1))
Dim ServerAddr As IPAddress = IPAddress.Parse(Params(0))

server = New TcpListener(ServerAddr, port)

....
....
Menee ja aloittaa kuuntelijan onnistuneesti


Form luokasta buttoni joka kutsuu listeneri luokkaa:

Dim TcpListenClass As New TcpListenerClass
TcpListenClass.Main()


Sanokaahan nyt mikä menee väärin kun ei kerran mitään virhettäkään enää pukkaa?

Kili 17:12 16.3.12 
Tein testin jossa rtb ja kaksi buttonia.

Formi luokan koodi:
Imports System
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms

Public Class Form1
' This delegate enables asynchronous calls for setting
' the text property on a TextBox control.
Delegate Sub SetTextCallback(ByVal [text] As String)

' This thread is used to demonstrate both thread-safe and
' unsafe ways to call a Windows Forms control.
Private demoThread As Thread = Nothing

Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Me.demoThread = New Thread( _
New ThreadStart(AddressOf Me.ThreadProcSafe))

Me.demoThread.Start()
End Sub

Public Sub ThreadProcSafe()
Me.SetText("This text was set safely.")
End Sub

Public Sub SetText(ByVal [text] As String)

' InvokeRequired required compares the thread ID of the
' calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
If Me.RichTextBox1.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText)
Me.Invoke(d, New Object() {[text]})
Else
Me.RichTextBox1.AppendText(text & vbNewLine)
End If
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim Threadi As New Class1
Threadi.main()
End Sub
End Class

Threadi luokan koodi Class1:
Imports System
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms

Public Class Class1
' This delegate enables asynchronous calls for setting
' the text property on a TextBox control.
Delegate Sub SetTextCallback(ByVal [text] As String)

' This thread is used to demonstrate both thread-safe and
' unsafe ways to call a Windows Forms control.
Private demoThread1 As Thread = Nothing

Public Sub main()
Me.demoThread1 = New Thread( _
New ThreadStart(AddressOf ThreadProcSafe1))

Me.demoThread1.Start()
End Sub

Public Sub ThreadProcSafe1()
Me.SetText1("This text was set safely 2.")
End Sub


Public Sub SetText1(ByVal [text] As String)

' InvokeRequired required compares the thread ID of the
' calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
If Form1.RichTextBox1.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText1)
Form1.Invoke(d, New Object() {[text]})
Else
Form1.RichTextBox1.AppendText(text & vbNewLine) 'Tähän mennään #1#
End If
End Sub


Public Sub New()

End Sub

Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub
End Class

Kun button1 kirjoittelee tekstiä formi luokan sisällä niin kaikki menee oikein ja teksti ilmestyy rtb komponenttiin.
Button 2 menee #1# kautta ja tekstiä tai mitään virhettä ei tule? Eli miten tuolta toisen luokan sisältä onnistutaan kirjoitamaan formille tavaraa?
editoitu: 18:32 16.3.12
Jari_Kettunen 18:25 16.3.12 
Luokalle parametrina lomake niin viritys toimii. (me:n viljely koodissa on turhaa)


vb
Imports System
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms

Public Class Class1
    Delegate Sub SetTextCallback(ByVal [text] As String)
    Private demoThread1 As Thread = Nothing
    Private parentForm As Form1


    Public Sub main(f As Form1)
        'Laitetaan isä talteen
        parentForm = f
        demoThread1 = New Thread( _
        New ThreadStart(AddressOf ThreadProcSafe1))

        demoThread1.Start()
    End Sub

    Public Sub ThreadProcSafe1()
        SetText1("This text was set safely 2.")
    End Sub


    Public Sub SetText1(ByVal [text] As String)

        'Laitetaan isälomakkeelle data kohdalleen
        If parentForm.RichTextBox1.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf SetText1)
            parentForm.Invoke(d, New Object() {[text]})
        Else
            parentForm.RichTextBox1.AppendText(text & vbNewLine) 'Tähän mennään #1#
        End If
    End Sub



    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub
End Class
 


Ja pääformi

vb

Imports System
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms

Public Class Form1
    ' This delegate enables asynchronous calls for setting
    ' the text property on a TextBox control.
    Delegate Sub SetTextCallback(ByVal [text] As String)

    ' This thread is used to demonstrate both thread-safe and
    ' unsafe ways to call a Windows Forms control.
    Private demoThread As Thread = Nothing

    Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        demoThread = New Thread( _
        New ThreadStart(AddressOf Me.ThreadProcSafe))

        demoThread.Start()
    End Sub

    Public Sub ThreadProcSafe()
        SetText("This text was set safely.")
    End Sub

    Public Sub SetText(ByVal [text] As String)

        If RichTextBox1.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf SetText)
            Invoke(d, New Object() {[text]})
        Else
            RichTextBox1.AppendText(text & vbNewLine)
        End If
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim Threadi As New Class1
        'Huomaa parametrina isäntä lomake
        Threadi.main(Me)
    End Sub

   
End Class



 
Kili 18:38 16.3.12 
Kiitoksia!
En nyt enää ole ohjelman parissa mutta tuli vielä tuosta rivistä:
'Huomaa parametrina isäntä lomake
Threadi.main(Me)

mieleen, että miten onnistuu lomakkeen vieminen parametrinä jos threadille annetaan jo kaksi string tyyppistä parametria ja lomake parametri?
Meneekö ihan parametri taulukkona jonka tyyppi on object?

editoitu: 19:42 16.3.12
Jari_Kettunen 19:37 16.3.12 
Näiden threadien kanssa sekoaa usein omaan näppäryyteensä ja kannattaa olla tarkkana. Tässähän nyt luodaan luokka jonka main metodia kutsuttiin joka sitten käynnisti luokan sisäisen threadin. Koodista käynee esille mitä tarkoitan. Esimerkkikoodissa käynnistetäään threadit jotka kirjoittavat ikiloopissa RichTextBoxin vuorotellen ja toiset painikkeet sitten pysäyttävät threadin. Lisäksi treadit kannattaa sammuttaa ennen lomakkeen sulkeutumista vaikkapa koodin esittämällä tavalla.


vb

Imports System
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms

Public Class Form1
    Delegate Sub SetTextCallback(ByVal [text] As String)

    Private demoThread As Thread = Nothing
    Private Threadi2 As Class1


    Public Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If demoThread Is Nothing Then
            demoThread = New Thread( _
            New ThreadStart(AddressOf Me.ThreadProcSafe))
        Else
            demoThread.Abort()
            demoThread = New Thread( _
            New ThreadStart(AddressOf Me.ThreadProcSafe))
        End If
        demoThread.Start()
    End Sub

    Public Sub ThreadProcSafe()
        Dim i As Integer = 1

        While True
            System.Threading.Thread.Sleep(1000)
            SetText("a" + i.ToString())
            i = i + 1
        End While

    End Sub

    Public Sub SetText(ByVal [text] As String)

        If RichTextBox1.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf SetText)
            Invoke(d, New Object() {[text]})
        Else
            RichTextBox1.AppendText(text & ",")
        End If

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        If Threadi2 Is Nothing Then
            Threadi2 = New Class1
        Else
            Threadi2.StopThread()
            Threadi2 = New Class1
        End If
       
        'Huomaa parametrina isäntä lomake
        Threadi2.main(Me)
    End Sub

   
    Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
        Threadi2.StopThread()
        Threadi2 = Nothing

    End Sub

    Private Sub Button4_Click(sender As System.Object, e As System.EventArgs) Handles Button4.Click

        demoThread.Abort()

        demoThread = Nothing

    End Sub

    Private Sub Form1_FormClosing(sender As System.Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        If Not demoThread Is Nothing Then
            demoThread.Abort()
        End If
        If Not Threadi2 Is Nothing Then
            Threadi2.StopThread()
        End If

    End Sub
End Class
 


ja luokka

vb
Imports System
Imports System.ComponentModel
Imports System.Threading
Imports System.Windows.Forms



Public Class Class1
    Delegate Sub SetTextCallback(ByVal [text] As String)
    Private demoThread1 As Thread = Nothing
    Private parentForm As Form1


    Public Sub main(f As Form1)
        'Laitetaan isä talteen
        parentForm = f
        demoThread1 = New Thread( _
        New ThreadStart(AddressOf ThreadProcSafe1))
        demoThread1.Start()
    End Sub
    Public Sub StopThread()
        demoThread1.Abort()
    End Sub

    Public Sub ThreadProcSafe1()
        Dim i As Integer = 1

        While True
            System.Threading.Thread.Sleep(1000)
            SetText1("B" + i.ToString())
            i = i + 1
        End While


    End Sub


    Public Sub SetText1(ByVal [text] As String)

        'Laitetaan isälomakkeelle data kohdalleen
        If parentForm.RichTextBox1.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf SetText1)
            parentForm.Invoke(d, New Object() {[text]})
        Else
            parentForm.RichTextBox1.AppendText(text & ",") 'Tähän mennään #1#
        End If
    End Sub



    Protected Overrides Sub Finalize()
        MyBase.Finalize()
    End Sub
End Class
 
editoitu: 20:30 16.3.12
Jari_Kettunen 20:20 16.3.12 
Kili kirjoitti:
Kiitoksia!
En nyt enää ole ohjelman parissa mutta tuli vielä tuosta rivistä:
'Huomaa parametrina isäntä lomake
Threadi.main(Me)

mieleen, että miten onnistuu lomakkeen vieminen parametrinä jos threadille annetaan jo kaksi string tyyppistä parametria ja lomake parametri?
Meneekö ihan parametri taulukkona jonka tyyppi on object?



No tämä on vähän jo olipohjelmoinnin asioita. Jos katsot metodia joka threadin käynnistyksessä annetaan ja mietit mikä on metodin luokkaympäristö ja mitä se näkee niin ehkä homma vähän aukeaa. Net-ympäristössä kannattaa ensin pois oppia globaaleiden muuttujien käytöstä.

Sinällään jos tässä sanoo jotain luokkien constructoreista niin tulee silmille heti. On kaksi koulukuntaa toinen on sitä mieltä että constuktoriin pitää laittaa kaikki parametrit ja sitten tehdä niin monta wrapperi constuctoria että vanha koodi toimii. Itse taas pidän enemmän public propertyistä ja "parametrittomasta" constructorista. Helpottaa vastuullista luokan rajapinnan laajentamista vahingoittamatta vanhan koodin toimintaa. Button 3 seuraavassa koodissa tai button 4 vanhalla tavalla. Kieleksi kannattaa vaihtaa c# syntyy luettavampaa koodia.


C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication5
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            label1.Text = new Class1().Say();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            label1.Text = new Class1("Hello","World").Say();
   
        }

        private void button3_Click(object sender, EventArgs e)
        {
            label1.Text = new Class1() { Hip = "Hello", Hei = "World" }.Say();
   
        }

        private void button4_Click(object sender, EventArgs e)
        {
            var x =new Class1();
            x.Hip = "Hello";
            x.Hei = "World";
            label1.Text=x.Say();
   
        }
   
    }
}
 

Ja luokka

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WindowsFormsApplication5
{
    public class Class1
    {
        public string Hip {get;set;}
        public string Hei { get; set; }

        public Class1()
        {
            Hip = "Hello";
            Hei = "World";
        }
        public Class1(string hip,string hei)
        {
            Hip = hip;
            Hei = hei;
        }

        public string Say()
        {
            return Hip + " " + Hei;
        }
    }
}