Archief - [C#] Repaint-probleem bij Threading

Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.

VenomGameworld

Legacy Member
Hallo,

ik ben momenteel bezig met een projectje om de groottes van partities van de harde schijf grafisch voor te stellen. Het uitlezen werkt, maar wanneer ik threading gebruik om deze info om de x aantal seconden/minuten te updaten, krijg ik een error bij het opnieuw aanroepen van de onPaint-methode.

De error is de volgende:
InvalidOperationException was unhandled
Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on


Dit is de code van de constructor:
Code:
Thread t1 = new Thread(new ThreadStart(GetData));
t1.Start();

paintDoorlopen = false;

Dit is de code van de overschreven onPaint-methode:
Code:
                Color kleur = Color.FromArgb(73, 73, 73);
                SolidBrush brush = new SolidBrush(kleur);
                Bitmap afbeelding = new Bitmap(pad);
                Graphics g = e.Graphics;

                // Tekenen van kader
                System.Drawing.Extended.ExtendedGraphics kader = new System.Drawing.Extended.ExtendedGraphics(g);
                kader.FillRoundRectangle(brush, 15.5F, 2.5F, 220.5F, 50.5F, 10.5F);

                // Tekenen van balk
                kleur = Color.FromArgb(118, 118, 118);
                brush = new SolidBrush(kleur);
                g.FillRectangle(brush, 25.5F, 35.5F, 195.0F, 5.5F);

                // Vullen van balk
                g.FillRectangle(new SolidBrush(Color.FromArgb(123, 188, 235)), gebruik);

                // Tekenen van pictogram
                g.DrawImage(afbeelding, 2, 4);

                // Tekenen van tekst
                g.DrawString(vrij.ToString() + "G vrij van " + totaal.ToString() + "G - " + (gebruik.Width / 2) + "%",
                    new Font("Microsoft Sans Serif", 9), new SolidBrush(Color.White), 60.0F, 20.0F);

                // Opruimen
                //pad = null;
                kader.Graphics.Dispose();
                brush.Dispose();
                afbeelding.Dispose();
                g.Dispose();

En dit is de code van de GetData-methode die in een nieuwe thread wordt uitgevoerd:
Code:
if (paintDoorlopen == false)
            {
                paintDoorlopen = true;
                Thread.Sleep(5000);
            }

// ... nog wat code

this.Refresh();

Thread.Sleep(10000);

De error vindt plaats bij de this.Refresh();.
Is er iemand die weet hoe ik dit het best kan oplossen?

Alvast bedankt!

Krueger

Legacy Member
Het probleem is dat je de paint methode enkel kan oproepen vanaf de main thread, en niet vanaf een zlf gecreerde thread.
Het eenvoudigst is om in je zelf gecreërde thread een delegate te gebruiken, waarbij je de paint functie Invoked.
De syntax ontsnapt me even, maar het is iets in de aard van:

Delegate void refreshHandler();
refreshHandler handler = new refreshHandler(refreshFunctie);
private void refreshFunctie()
{
this.refresh();
}

En in je code doe je dan:
this.BeginInvoke(handler);

VenomGameworld

Legacy Member
Bedankt, het werkt.

Nu ben ik van plan om een while lus (met een boolean als argument) te gebruiken binnen de methode van de thread (GetData). Is het dan voldoende om bij het afsluiten van het programma de boolean op false te zetten en nadien de thread af te sluiten met methode .abort()?
Of is er een beter manier? Want het volgende verschijnt in de debug console:
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
Moet deze exception expliciet opgevangen worden?

Krueger

Legacy Member
Dat is idd voldoende. Die exceptie die optreed is normaal, en is gewoon de normale manier van c@ (of windows i dunno) om een gecreeërde thread te beïndigen, opvangen van die exceptie is dan ook niet nodig.

VenomGameworld

Legacy Member
Ik heb nu de onPaint-methode, de delegete-methode, de thread-methode (GetData) en een methode om de thread te beëindigen in een aparte klasse gestoken zodat ik er meerdere instanties van kan aanmaken.
Hiervoor heb ik de klasse gebaseerd op moederklasse Panel, is dit een goeie keuze voor deze doeleinden?

Enkel de constructor ziet er nu iets anders uit:
Code:
public HDmonitor()
        {
            handler = new refreshHandler(refreshFunctie);

            t1 = new Thread(new ThreadStart(GetData));
            t1.Start();

            doorgaan = true;
        }

Wanneer ik de klasse als volgt aanroep:
schijfC = new Meters.HDmonitor();

krijg ik na enkele seconden in de thread-methode een error op de lijn met:
this.BeginInvoke(handler);

De error is deze:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

De onPaint-methode wordt ook niet aangeroepen want er verschijnt een leeg formulier op het scherm. Wat doe ik fout?

Alvast bedankt!

Krueger

Legacy Member
Ik weet niet of ik 100% meeben, maar voor zover ik begrijp, zou je beter een UserControl van die klassen maken. Dan kan je er ook makkelijk meerdere op 1 form zetten.
Ik zie niet onmiddellijk in wat het voordeel is van een Panel te gebruiken als basisklasse.

Ik zou dan het starten van de thread niet in de constructor doen, maar in het load-event van de user control.

VenomGameworld

Legacy Member
Bedankt, ik heb er een UserControl van gemaakt en het werkt terug, geen errors meer.
Het archief is een bevroren moment uit een vorige versie van dit forum, met andere regels en andere bazen. Deze posts weerspiegelen op geen enkele manier onze huidige ideeën, waarden of wereldbeelden en zijn op sommige plaatsen gecensureerd wegens ontoelaatbaar. Veel zijn in een andere tijdsgeest gemaakt, al dan niet ironisch - zoals in het ironische subforum Off-Topic - en zouden op dit moment niet meer gepost (mogen) worden. Toch bieden we dit archief nog graag aan als informatiedatabank en naslagwerk. Lees er hier meer over of start een gesprek met anderen.
Terug
Bovenaan