Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Εχω τον παρακατω κωδικα σε WinForms αλλα υπαρχει το εξης προβλημα. Οταν κανω κλικ στο button1 ξεκιναει ο κωδικας να μετραει και οταν κατα την διαρκεια της καταμετρησης κανω κλικ στο button2  δεν μου εμφανιζει το μηνυμα παρα μονο αν κανω και δευτερο κλικ. Το ιδιο ισχυει αν κανω κλικ στο κουμπι Χ της φορμας (χρειαζετε 2 φορες κλικ για να κλεισει). Παλιοτερα που δουλευα με την VB6 δεν ειχα αυτο το προβλημα με την DoEvents. Σκεφτηκα να κανω χρηση το BackgroundWorker και στον κωδικα του button1 να βαλω στη θεση του Work() το RunWorkerAsync(). Το προβλημα ειναι οτι αν το κανω αυτο ο κωδικας που υπαρχει απο κατω το μηνυμα "end" θα εμφανιστει αμεσως και οχι μετα το τελος της εργασιας. Φυσικα υπαρχει η λυση με το συμβαν RunWorkerCompleted οπου εκει μεσα μπορω να βαλω το MessageBox.Show("end"). Ολα καλα μεχρι εδω με το BackgroundWorker. Τι γινεται ομως οταν καλω την Wok() σε διαφορετικα σημεια μεσα στο project οπου μετα την Work ο κωδικας που ακολουθει δεν ειναι ιδιος;

Να κανω χρηση πολλαπλα BackgroundWorkers για καθε κληση της Work δεν ειναι καθολου καλη λυση.

Γενικα ο η χρηση της DoEvents με βολευει απλως δεν ανταποκρινεται με την πρωτη και ειναι αυτο που θελω να λυσω.

 

Εχετε να προτεινεται κατι;

 

Ευχαριστω

        private void button1_Click(object sender, EventArgs e)
        {
            Work();
            MessageBox.Show("end");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            MessageBox.Show("AAA");
        }

        private void Work()
        {
            for (int i = 1; i <= 20000; i++)
            {
                label1.Text = i.ToString();
                Application.DoEvents();
            }
        }
Δημοσ.

Don't DoEvents  :-) . 

 

Μια άλλη μεθοδος ειναι με delegate. Το μειονέκτημα ειναι ότι η MessageBox θα κληθεί σε άλλο thread.

        delegate void WorkDel();
        private void button1_Click(object sender, EventArgs e)
        {
            WorkDel t = Work;
            t.BeginInvoke((IAsyncResult i) => MessageBox.Show("end"), null);
        }

Η σωστή λύση ειναι με BackgroundWorker. Το ότι θες διαφορετικα μηνυματα στο Completed εχει να κανει με τη λογικη στη σχεδίαση της εφαρμογής σου.

Δημοσ.

Ψαχνοντας στο google βρηκα οτι χρειαζεται να βαλω το button1.Capture = false οπως φαινεται παρακατω.

Ετσι το προβλημα λυθηκε.

        private void button1_Click(object sender, EventArgs e)
        {
            button1.Capture = false;
            Work();
            MessageBox.Show("end");
        }

Τον κωδικα που εδωσες το αλλαξα οπως φαινεται παρακατω. Νομιζω πως ετσι ειναι καλυτερα

//delegate void WorkDel();
private void button1_Click(object sender, EventArgs e)
{
    //WorkDel t = Work;
    Action t = Work;
    t.BeginInvoke((IAsyncResult i) => MessageBox.Show("end"), null);
}
Δημοσ.

Δες και αυτό το thread για τις παρενέργειες της DoΕvents. Απ οτι καταλαβα δεν πρεπει να καλείται (σχεδον) ποτε.

http://stackoverflow.com/questions/5181777/use-of-application-doevents

 

Γενικά οταν έχεις καποια εργασία που παίρνει χρόνο την κάνεις σε αλλο thread, δεν "ξεπαγώνεις" το GUI ανα τακτα διαστήματα. 

Δημοσ.

albNik thanks για την βοηθεια. Ισως αντικαταστησω την DoEvents με τον κωδικα που εδωσες. Τωρα εχω το εξης προβλημα με τον παρακατω κωδικα. Βγαζει error στο BeginInvoke. Θελω να καλει την Work  η οποια εχει μια παραμετρο. Δεν ξερω τι κανω λαθος.

        private void button1_Click(object sender, EventArgs e)
        {      
            Action<int> t = Work;
            t.BeginInvoke((IAsyncResult i, int k) => MessageBox.Show("end"), null);
        }

        private void Work(int k)
        {
            for (int i = 1; i <= 20000; i++)
            {
                label1.Text = i.ToString();
            }
        }
Δημοσ.

Ετσι θα τη καλέσεις

t.BeginInvoke(1234 ,(IAsyncResult i) => MessageBox.Show("end"), null);

Ενα άλλο θεμα που έχεις με threads ειναι ότι δεν μπορείς πειράζεις τo GUI άμεσα (label1.Text = i.ToString();)

google InvokeRequired

Δημοσ.

Ενα άλλο θεμα που έχεις με threads ειναι ότι δεν μπορείς πειράζεις τo GUI άμεσα (label1.Text = i.ToString() ;)

google InvokeRequired

 

Ο παρακατω κωδικας που δοκιμασα σε WinForms παιζει κανονικα όταν τον τρεχω με Ctrl+F5. Αν πατησω μονο F5 και μετα το buttton1 χτυπαει error στο label1.Text = c.ToString();

Δεν ξερω αν εννοεις αυτο ή κατι αλλο.

    public partial class Form1 : Form
    {
        private Thread t;

        public Form1()
        {
            InitializeComponent();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            MessageBox.Show("AAAA");
        }

        private void count()
        {
            for (int c = 1; c <= 10000; c++)
            {
                label1.Text = c.ToString();
                label1.Refresh();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //count();
            t = new Thread(count);
            t.Start();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            t.Abort();
        }
    }

Δημοσ.

Για τρεξτο με debug  (F5)  .  :-D

 

Γενικα σε Release θα παιξει τις 99/100 φορες. Αλλα θα ειναι ενα απο τα πιο σπαστικά τυχαία bugs. It sometimes crashes

 

https://www.google.gr/search?q=update+controls+from+another+thread&oq=update+controls+from+another+thread&aqs=chrome.0.57&sourceid=chrome&ie=UTF-8

 

Κριμα γιατι νομιζα οτι σε Release θα παιζει τις 100/100 φορες. Οσες φορες το εχω δοκιμασει δεν ειχα κανενα προβλημα. Τι να πω ολη αυτη η διαδικασια που λεει το link για να αποτρεψουμε το 1%;

Δημοσ.

ημαρτον!

Btw τσ μπορεις να δεις και async await αν εισαι σε c# 4.5 ? 5 ? (ποτε μπηκε αυτο; )

 

 

και να κανεις κατι τετοιο

private async void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 10000; i++)
    {
        await Task.Delay(1);
        label1.Text = i.ToString();
    }
}

αν και θα επρεπε να δουλευει και αυτο αλλα δεν

private async void button1_Click(object sender, EventArgs e)
{
    for (int i = 0; i < 10000; i++)
    {
        label1.Text =await Task.FromResult( i.ToString() );
    }
}
Δημοσ.

Τον κωδικα που παρεθεσα στο #7 τον εκανα .exe και ετρεξα το εκτελεσιμο ενω ειχα ανοικτο το winamp το οποιο επαιζε ενα βιντεο. Οταν πατησα το button1 για να ξεκινησει να μετραει, το βιντεο κολλουσε, εχανε frames. Γιατι;

Για να μην ανοιγω νεο θεμα εχει βγει .net framework 5; Τα windows 8 ποιο framework εχουν προεγκατεστημενο το 4 ή 4.5;

Δημοσ.

Ο σωστός τρόπος να το κάνεις είναι με await και IProgress<T> ώστε να δέσεις σαν continuation το messagebox μετά την ολοκλήρωση του task του worker.
 

public Form1()
{
    var progress = new Progress<int>(_ => {
        label1.Text = _.ToString();
    });

    InitializeComponent(); 
    button1.Click += async delegate {
        await worker(progress);
        MessageBox.Show("end");
    };

    button2.Click += delegate {
        MessageBox.Show("AAA");
    };
}

public async Task worker(IProgress<int> progress)
{
    for (int i = 1; i <= 20000; i++) {
        await Task.Delay(100);
        progress.Report(i);
    }
}

Το delay προσομοιώνει το actual work που έχεις να κάνεις.

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...