geo1st487 Δημοσ. 27 Ιουνίου 2013 Δημοσ. 27 Ιουνίου 2013 Εχω τον παρακατω κωδικα σε 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(); } }
albNik Δημοσ. 27 Ιουνίου 2013 Δημοσ. 27 Ιουνίου 2013 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 εχει να κανει με τη λογικη στη σχεδίαση της εφαρμογής σου.
geo1st487 Δημοσ. 27 Ιουνίου 2013 Μέλος Δημοσ. 27 Ιουνίου 2013 Ψαχνοντας στο 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); }
albNik Δημοσ. 27 Ιουνίου 2013 Δημοσ. 27 Ιουνίου 2013 Δες και αυτό το thread για τις παρενέργειες της DoΕvents. Απ οτι καταλαβα δεν πρεπει να καλείται (σχεδον) ποτε. http://stackoverflow.com/questions/5181777/use-of-application-doevents Γενικά οταν έχεις καποια εργασία που παίρνει χρόνο την κάνεις σε αλλο thread, δεν "ξεπαγώνεις" το GUI ανα τακτα διαστήματα.
geo1st487 Δημοσ. 27 Ιουνίου 2013 Μέλος Δημοσ. 27 Ιουνίου 2013 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(); } }
albNik Δημοσ. 27 Ιουνίου 2013 Δημοσ. 27 Ιουνίου 2013 Ετσι θα τη καλέσεις t.BeginInvoke(1234 ,(IAsyncResult i) => MessageBox.Show("end"), null); Ενα άλλο θεμα που έχεις με threads ειναι ότι δεν μπορείς πειράζεις τo GUI άμεσα (label1.Text = i.ToString() google InvokeRequired
geo1st487 Δημοσ. 27 Ιουνίου 2013 Μέλος Δημοσ. 27 Ιουνίου 2013 Ενα άλλο θεμα που έχεις με 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(); } }
albNik Δημοσ. 27 Ιουνίου 2013 Δημοσ. 27 Ιουνίου 2013 Για τρεξτο με debug (F5) . Γενικα σε 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
geo1st487 Δημοσ. 27 Ιουνίου 2013 Μέλος Δημοσ. 27 Ιουνίου 2013 Για τρεξτο με debug (F5) . Γενικα σε 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%;
albNik Δημοσ. 28 Ιουνίου 2013 Δημοσ. 28 Ιουνίου 2013 Τρεχει cross-thread χωρις invoke σε release; wtf? Και σε debug με χακεριες http://stackoverflow.com/questions/13345091/c-sharp-checkforillegalcrossthreadcalls
παπι Δημοσ. 28 Ιουνίου 2013 Δημοσ. 28 Ιουνίου 2013 ημαρτον! 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() ); } }
geo1st487 Δημοσ. 28 Ιουνίου 2013 Μέλος Δημοσ. 28 Ιουνίου 2013 Τον κωδικα που παρεθεσα στο #7 τον εκανα .exe και ετρεξα το εκτελεσιμο ενω ειχα ανοικτο το winamp το οποιο επαιζε ενα βιντεο. Οταν πατησα το button1 για να ξεκινησει να μετραει, το βιντεο κολλουσε, εχανε frames. Γιατι; Για να μην ανοιγω νεο θεμα εχει βγει .net framework 5; Τα windows 8 ποιο framework εχουν προεγκατεστημενο το 4 ή 4.5;
παπι Δημοσ. 28 Ιουνίου 2013 Δημοσ. 28 Ιουνίου 2013 Εχανε frame γιατι μια τετοια for θελει παρα πολυ cpu. Δεν λεω για .net 4.5 ή 5 αλλα για την γλωσσα C# http://en.wikipedia.org/wiki/C_Sharp_(programming_language)#Versions
Portmaster Δημοσ. 30 Ιουνίου 2013 Δημοσ. 30 Ιουνίου 2013 Ο σωστός τρόπος να το κάνεις είναι με 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 που έχεις να κάνεις.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα