předávání hodnot mezi více vlákny   zodpovězená otázka

VB.NET

Dobrý den,

prosím o radu jak předat hodnotu z jiného vlákna a z jiného modulu. Pokud je vše v hlavním formuláři, tak mi to vše funguje. Ale jakmile přidám module a přesunu to tam, tak to přestane fungovat. Program je následující.

Mám formulář na něm textbox a 2xbutton, kód je následující.

Imports System.Threading
Delegate Sub SetTextCallback(ByVal [text] As String)
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Module1.start()
    End Sub

    Private Sub ThreadProcSafe2()
        SetText2("Button 2")
    End Sub

    Public Sub SetText2(ByVal [text] As String)
        If Me.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf SetText2)
            Invoke(d, New Object() {[text]})
        Else
            Label1.Text = [text]

        End If
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim demoThread2 = New Thread(New ThreadStart(AddressOf Me.ThreadProcSafe2))
        demoThread2.Start()
    End Sub
    
End Class

Imports System.Threading
Module Module1
    Public Sub start()
        Dim demoThread = New Thread(New ThreadStart(AddressOf ThreadProcSafe))
        demoThread.Start()
    End Sub

    Public Sub ThreadProcSafe()
        SetText("Button 1")
    End Sub

    Private Sub SetText(ByVal [text] As String)
        If Form1.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf SetText)
            Form1.Invoke(d, New Object() {[text]})
        Else
            Form1.Label1.Text = [text]
        End If
    End Sub
End Module

tlačítko 1 nic neudělá, jelikož se vše volá z modulu, tlačítko 2 zapíše text kam má. Je nějaká možnost aby to fungovalo i na tlačítko 1?

S treadem začínám, tak prosím popsat jak pro blbce, děkuji :-)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

V aplikacích tohoto typu je potřeba rozlišovat tzv. UI thread (zpravidla současně hlavní thread) a ostatní worker thready. ovládací prvky uživatelského rozhraní lze měnit pouze z UI threadu. U požadavku z worker threadu je potřeba předat řízení zpět na UI thread a ten nechat UI změnit.

To lze provést buď obecně přes SynchronizationContext (abstrakce konkrétní architektury aplikace jako Windows Forms/WPF apod.) nebo konkrétně u Windows Forms to lze provést metodou Control.Invoke resp. BeginInvoke.

To jestli to máte v modulu nebo ne s tím nesouvisí, ale možná bude problém v tom, že vám Form1. nemusí odkazovat na správnou instanci aktuálně otevřeného formuláře.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Děkuji za reakci, ale stále se mi nedaří najít na googlu, jak to udělat. Rád bych použil Invoke. Všechny odkazy co jsem procházel uvádí příklady vždy z hlavního formuláře, tam funguje i můj kód. Ale jakmile procedury přemístím do modulu, tak to přestane fungovat. Sice program při krokování na řádku 45 se tváří, že tam ukládá správný text, žádnou chybu to nenapíše, ale ve výsledku tam ten text není. Nemohl by jste prosím uvést kód jak na to. Nebo pokud by jste věděl o nějakém odkazu, kde se to řeší.

Děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Já bych místo modulu udělat třídu, pro komunikaci s formulářem bych používal události, pro spouštění práce na jiném než hlavním threadu bych použil Task a pro předání řízení zpět na UI/main thread bych použil SynchronizationContext.

Kód v C#:

public partial class Form1 : Form
{
    private Worker Worker;

    public Form1()
    {
        InitializeComponent();

        this.Worker = new Worker();
        this.Worker.Completed += Worker_Completed;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Run(() => this.Worker.SomeWork());
    }

    private void Worker_Completed(object sender, EventArgs e)
    {
        label1.Text = "Completed at " + DateTime.Now.ToString("HH:mm:ss");
    }
}

internal class Worker
{
    private SynchronizationContext SynchronizationContext;

    public event EventHandler Completed;

    public Worker()
    {
        this.SynchronizationContext = SynchronizationContext.Current;
    }

    public void SomeWork()
    {
        //Work
        Thread.Sleep(TimeSpan.FromSeconds(2));

        this.SynchronizationContext.Post(_ => OnCompleted(), null);
    }

    private void OnCompleted()
    {
        var handler = Completed;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

Kód ve VB.NET (z converteru, možná to chce trochu poupravit, ve VB.NET nedělám):

Public Partial Class Form1
	Inherits Form
	Private Worker As Worker

	Public Sub New()
		InitializeComponent()

		Me.Worker = New Worker()
		AddHandler Me.Worker.Completed, AddressOf Worker_Completed
	End Sub

	Private Sub button1_Click(sender As Object, e As EventArgs)
		Task.Run(Function() Me.Worker.SomeWork())
	End Sub

	Private Sub Worker_Completed(sender As Object, e As EventArgs)
		label1.Text = "Completed at " & DateTime.Now.ToString("HH:mm:ss")
	End Sub
End Class

Friend Class Worker
	Private SynchronizationContext As SynchronizationContext

	Public Event Completed As EventHandler

	Public Sub New()
		Me.SynchronizationContext = SynchronizationContext.Current
	End Sub

	Public Sub SomeWork()
		'Work
		Thread.Sleep(TimeSpan.FromSeconds(2))

		Me.SynchronizationContext.Post(Function(_) OnCompleted(), Nothing)
	End Sub

	Private Sub OnCompleted()
		Dim handler = Completed
		RaiseEvent handler(Me, EventArgs.Empty)
	End Sub
End Class
nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

děkuji mnohokráte za pomoc, už to zkouším a vypadá to, že to bude fungovat :-)

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback