Avatar billede 123maka Nybegynder
26. januar 2009 - 16:22 Der er 9 kommentarer og
2 løsninger

Opbygning af GUI programmer og tråde

Hej eksperten.

Jeg er ved at lave en mindre applikation og vil gerne binde noget GUI på min applikation. Pt. fungerer det som et kommandolinje baseret program, som kører i uendelig løkke. I dens løkke ændrer den data.
Før løkken starter sættes der nogle værdier som er statiske for løkken.

Jeg tænkte at lave et program der vha. WinForms satte de første statiske variabler og satte løkken igang. Men de data som løkken ændrer skal jo vises i min GUI, og måske også ændres fra min GUI. Og de kan ikke køre i samme tråd, men de skal begge kunne dele information.

Jeg har søgt nettet tyndt, nogle mener delegates er løsningen, andre noget andet. Men synes ikke man nogensinde får indblikket i hvordan man designer noget så man ikke låser sin GUI-tråd.

Kan nogle pege mig i en retning? Evt. komme med noget simpelt kode så jeg selv kan udbygge, eller bare komme med en klog kommentar?

Hilsen mig
Avatar billede torbenkoch Nybegynder
26. januar 2009 - 16:30 #1
Det er som hovedregel kun GUI/Main-tråden, der må røre ved GUI-dele, f.eks. sætte text i en tekstboks. MS har dog lavet en hjælpefunktion på Control: Invoke, som gør dette meget nemmere end i "de gode, gamle dage".

Se: http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

Her er en gut, der har nogle ret gode eksempler på netop det du vil: http://weblogs.asp.net/justin_rogers/articles/126345.aspx
Avatar billede kalp Novice
26. januar 2009 - 16:37 #2
Meget groft beskrevet.

1. sørg for din løkke og dens logik ligger i en metode, som kan kaldes et andet sted fra i dit applikation.

2. opret en tråd som kalder denne metode.. kan gøres nemt med f.eks
Thread thread = new Thread(new ThreadStart(dinMetodesNavnUdenParanteser));
thread.Start();

3. når din metode skal opdatere et element i din GUI skal du have GUI tråden til og gøre arbejdet.. kode kunne se ud som:

if(this.InvokeRequired){
  ParameterizedThreadStart doUpdate = new ParameterizedThreadStart(UpdateText);
  this.Invoke(doUpdate, "Et eller andet");
} else {
  updateText("Et eller andet");
}


private void updateText(string text){
label.Text = text;
}


og det er sådan set det.
kode er ikke skrevet i en editor så den kan have nogle bugs, men ideen er den:)
Avatar billede 123maka Nybegynder
26. januar 2009 - 18:01 #3
Wow.. man kommer til at skrive meget kode synes jeg :)

Kan det samme ikke opnås med noget Model View Presenter: http://aviadezra.blogspot.com/2008/10/model-view-presenter-design-pattern.html ?
Avatar billede aaberg Nybegynder
27. januar 2009 - 08:37 #4
Brug en BackgroundWorker! Den er lavet til formål der minder om dit. At lave flertrådet applikationer giver ofte flere problemer end det løser. BackgroundWorker klassen gør mange ting for dig, og den gør det rigtigt.

Et problem du vil støde på med det samme, hvis du bruger Thread klassen, som kalp foreslår, er at dit program kaster en fejlmeddelelse, hver gang du lukker programmet. Dette opstår, da formen bliver lukket/disposed før tråden, og når tråden derefter kalder Invoke, kastes der en fejl. BackgroundWorker håndterer dette for dig, så du slipper at tænke på, plus at den håndtere flere andre ting.

Når man skal kommunikere med BackgroundWorker tråden, går det via events, og man skal ikke kalde Invoke (Det gør BackgroundWorker klassen for dig).
Avatar billede aaberg Nybegynder
27. januar 2009 - 08:42 #5
Her kommer lige et eksempel.

Jeg har oprettet en Form i visual Studio. Fra toolbox'en har jeg trukket ind en Button, en ProgressBar og en BackgroundWorker. På BackgroundWorkeren har jeg sat WorkerReportsProgress propertien til true, og jeg abonnerer på DoWork eventet og ProgressChanged eventet.

Min kode ser således ud.

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApplication2
{
    public partial class BackgroundWorkerTestForm : Form
    {
        public BackgroundWorkerTestForm()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // starter BackgroundWorkeren.
            this.backgroundWorker1.RunWorkerAsync();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            //Dette er BackgroundWorker tråden. Jeg kører rundt i en løkke, og rapporterer progress.
            for (int i = 0; i < 100; i++)
            {
                backgroundWorker1.ReportProgress(i);
                Thread.Sleep(50);
            }
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = e.ProgressPercentage;
        }
    }
}
Avatar billede kalp Novice
27. januar 2009 - 20:04 #6
Der er masser af events på en form man kan lytte til før den lukkes så en evt. tråd kan afsluttes..

men i mit indlæg er det mere punkt 3 jeg ville fortælle om:)
den kode kan benyttes i en ThreadPool og andre i andre sammenhænge nemlig:)
Avatar billede 123maka Nybegynder
29. januar 2009 - 04:44 #7
Aha lækkert kode eksempel! Fik også en BackgroundWorker anbefalet andetstedsfra.
Den ser imidlertid ret nem ud at implementere, men er det korrekt at den kun kan fortælle den progress? For imidlertid virker det som om jeg vil kommunikere mere data ud til mine forms.
Avatar billede 123maka Nybegynder
30. januar 2009 - 13:08 #8
Har fundet en løsning som lidt løser mit problem. Men valgte også at bruge en backgroundworker til noget andet.

Min løsning er beskrevet her: http://kristofverbiest.blogspot.com/2007/02/simple-pattern-to-invoke-gui-from.html

Opret gerne svar fra jer allesammen.

Tak for hjælpen.
Avatar billede aaberg Nybegynder
30. januar 2009 - 13:31 #9
Du kan godt fortælle mere end bare et Progress tal. ProgressChangedEventArgs har i tillæg til ProgressPercentage propertien en property der hedder UserState, som du kan putte hvad som helst i.
Avatar billede 123maka Nybegynder
10. februar 2009 - 20:30 #10
Kalp opretter du ikke svar?
Avatar billede kalp Novice
10. februar 2009 - 20:47 #11
det får du her:)
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
Kurser inden for grundlæggende programmering

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