Avatar billede the_julle Praktikant
17. januar 2012 - 15:22 Der er 17 kommentarer og
1 løsning

Tilgå GUI i multitrådet programmering

Hej alle.

Jeg har lavet et lille program, som er delt op i en hovedtråd og en arbejdstråd. Hovedtråden skal hele tiden sørge for at GUI'en (Windows Forms) kører.

Jeg har dog lidt problemer med at tilgå GUI'en i min arbejdstråd. Jeg er klar over at man skal benytte delegate og invoke, men jeg kan simpelthen ikke få det til at lykkedes.

Er der nogen der er skrappe til det og vil tage et hurtigt kig på min kode. Jeg tænkte, at jeg kan sende den på jeres mail, da det ikke rigtig giver mening at skrive alt koden her.
Avatar billede arne_v Ekspert
17. januar 2012 - 15:26 #1
Du burde da sagtens kunne poste den relevante kode her.
Avatar billede the_julle Praktikant
17. januar 2012 - 15:31 #2
Joo, det kan jeg jo sagtens, men synes bare det bliver virkelig rodet, da her jo ikke er nogle code-tags.

Må jeg sende dig en mail i stedet (uden eksekverbare filer)?
Avatar billede arne_v Ekspert
17. januar 2012 - 15:41 #3
Hvis koden er rodet, saa var det maaske en ide at rydde lidt op i den!?!?

Et invoke eksempel fra lageret (simpel clock):

    public void Run()
    {
        while(true)
        {
            if(time.InvokeRequired)
            {
                time.Invoke((Action)(() => time.Text = DateTime.Now.ToString()));
            }
            else
            {
                time.Text = DateTime.Now.ToString();
            }
            Thread.Sleep(1000);
        }
    }
    public void StartClick(object sender, EventArgs e)
    {
        t = new Thread(Run);
        t.Start();
    }
    public void AbortClick(object sender, EventArgs e)
    {
        t.Abort();         
    }
Avatar billede the_julle Praktikant
17. januar 2012 - 15:50 #4
Jeg synes nu ikke min kode er rodet. Jeg har lavet to knapper og to radio-knapper, som jeg forsøger at lege med. Jeg tænkte bare det kunne være smart at sende projektet, så kunne i se min tanke, og hvordan jeg har anvendte delegate og Invoke. Det er nemlig en del anderledes end det du har givet som eksempel.
Avatar billede arne_v Ekspert
17. januar 2012 - 16:04 #5
du har noget GUI funktionalitet, enten kan det laves i en linie eller saa pakker du det ind i en metode saa du kan lave et metode kald i en linie

du tester at den linie/metode kald virker naar den kaldes paa GUI traaden (lav en midlertidig button og test via dens click metode)

saa skal din arbejds traad udfoere den linie/metode kald og det goeres med 7 linier som i mit eksempel
Avatar billede the_julle Praktikant
17. januar 2012 - 16:15 #6
Jeg er kun på et begynder stadie i C#, jeg sidder kun og roder med tingene for at blive bedre.

Jeg har her et skærmdump af min kode. Det er fair nok hvis du ikke vil kigge på det. Jeg spurgte også bare om der mon var nogle der havde tiden og lysten.

Windows Form, del1
http://i162.photobucket.com/albums/t244/the_julle/form1del1.png

Windows Form, del2
http://i162.photobucket.com/albums/t244/the_julle/form1del2.png

Arbejdstråd
http://i162.photobucket.com/albums/t244/the_julle/import.png
Avatar billede arne_v Ekspert
18. januar 2012 - 02:05 #7
Der er ingen grund til at goere det saa indviklet. Du bor kunne det samme med at have en start button click som starter en traad og en stop button click som saetter en volatile bool som du saa tester paa i traaden.
Avatar billede the_julle Praktikant
18. januar 2012 - 08:15 #8
Tak for svar.

Ehm. Men er det ikke også lidt det jeg har gjort? Og så har jeg oprettet nogle globale variable til at kunne stoppe tråden igen, ved tryk på en knap...?
Avatar billede the_julle Praktikant
18. januar 2012 - 09:30 #9
Nu har jeg lige lavet et nyt eksmpel.

namespace threads_msdn
{
    public partial class Form1 : Form
    {
        delegate void SetTextCallback(string text);
        private Thread demoThread = null;

        private TextBox textBox1;
        private Button setTextSafeBtn;

        public Form1()
        {
            InitializeComponent();
        }

        private void setTextSafeBtn_Click(object sender, EventArgs e)
        {
            this.demoThread = new Thread(new ThreadStart(this.ThreadProcSafe));

            this.demoThread.Start();
        }

        private void ThreadProcSafe()
        {
            this.SetText("This text was set safely.");
        }

        private void SetText(string text)
        {
            if (this.textBox1.InvokeRequired)
            {   
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox1.Text = text;
            }
        }
    }
}



Men jeg kan stadig ikke finde ud af hvordan man kan finde ud af om en checkbox er checked eller ej.
Avatar billede janus_007 Nybegynder
18. januar 2012 - 09:39 #10
Hej the_julle

Jeg kan ikke helt se hvad du prøver med de events, du skriver at du vha. events kan stoppe tråden, men som jeg ser det stoppes tråden ikke med en event (og havde forøvrigt også forventet m_workerThread.RequestStop()). Jeg kan ikke se din this.WorkerThreadFunction, men det er jo tråden som du starter der skal subscribe på en event som raises i form1 og det kan jeg ikke se :)

Anyway... Jeg ville nok bruge en SynchronizationContext, den er nem og fungerer perfekt med forms

http://msmvps.com/blogs/manoj/archive/2005/11/03/74120.aspx
Avatar billede the_julle Praktikant
18. januar 2012 - 10:08 #11
@janus. Jeg forstår godt det kan være svært at forstå min kode. Som jeg efterhånden har forstået det, laver man ikke threads sådan. Ideen fik jeg fra:
http://www.codeproject.com/KB/cs/workerthread.aspx

Jeg har kigget lidt på backgroundWorker, som du nævner. Som jeg hra forstået det bruges denne udelukkende til WindowsForms, og kan ikke bruge hvis man ønsker flere "normale" tråde?

private BackgroundWorker backgroundWorker1;

private void setTextBackgroundWorkerBtn_Click(object sender,EventArgs e)
        {
            this.backgroundWorker1.RunWorkerAsync();
        }

private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
        {
            this.textBox1.Text = "This text was set safely by BackgroundWorker.";
        }

Men igen: Hvor laver jeg et check på en checkbox, så jeg kan se om brugeren har markeret denne? Skal man desuden oprette en ny backgroundworker for hvert element man har i ens form?
Avatar billede the_julle Praktikant
18. januar 2012 - 11:07 #12
Jeg fandt den her guide:
http://www.codeproject.com/KB/threads/mtguide_1.aspx

Det er ikke meget forskelligt fra det jeg har lavet. Men han forklare heller ikke hvordan jeg læser værdien fra en checkbox, når jeg kører med to forskellige klasser.

Kan man lave en delegate funktion som returnere end værdi?
Avatar billede arne_v Ekspert
19. januar 2012 - 04:15 #13
ja - delegates kan godt returnere en vaerdi - og ja - invoke understoetter det
Avatar billede the_julle Praktikant
19. januar 2012 - 09:31 #14
Hmm. Jeg forsøger at returnere en værdi som fortæller om en checkbox er checked eller ej. Det gør fint så længe jeg ikke skal anvende Delegates, men kan simplethen ikke få det til at virke med Delegates og tråde.

Hvordan modificere jeg nedenstående kode til at returnere en værdi?


// Thread
Thread Worker;
       
// Delegate
delegate bool DelegateTest(System.Windows.Forms.CheckBox navn);
DelegateTest m_DelegateTest;

// Default constructor
public Form1()
{
    InitializeComponent();
}

// GUI
private void btn_start_Click(object sender, EventArgs e)
{
    m_DelegateTest = CheckCB;

    Worker = new Thread(ProcessRoutine);
    Worker.Start();
}

bool CheckCB(System.Windows.Forms.CheckBox navn)
{
    return navn.Checked;
}

//**********
// Thread
private void ProcessRoutine()
{
    bool test;

    this.BeginInvoke(this.m_DelegateTest, cb_end);
}
Avatar billede the_julle Praktikant
19. januar 2012 - 11:39 #15
Så lykkedes det endelig.

IAsyncResult check = this.BeginInvoke(this.m_DelegateTest, cb_end);
    if ((bool)EndInvoke(check))
          // Do something


Åbning af filer
Hvordan er tanken her når det skal foregår i et trådet program. Udfører man altid dette i main-tråden som også styre alle windows forms?
Avatar billede arne_v Ekspert
29. januar 2012 - 04:08 #16
Jeg forstaar stadigvaek ikke hvorfor den kode er saa kompleks. Det er en helt simpel opgave.

        void Button1MouseClick(object sender, MouseEventArgs e)
        {
            (new Thread(Run)).Start();
        }
        public void Run()
        {
            if((bool)Invoke((Func<bool>)(() => checkBox1.Checked)))
            {
                Invoke((Action)(() => label1.Text = "Checked"));
            }
        }

virkr fint.
Avatar billede the_julle Praktikant
01. februar 2012 - 08:44 #17
Jeg prøver at rode videre med det. Nu er jeg kommet godt i gang i hvert fald.

Hvis du opretter et svar får du point.

Tak for hjælpen.
Avatar billede arne_v Ekspert
01. februar 2012 - 15:48 #18
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester