Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Ανανέωση winform

Îåêßíçóå áðü ôï ìÝëïò serakar. Τελευταία δημοσίευση από το μέλος George Parissis στις 16-02-2012, 13:10. Υπάρχουν 7 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  12-02-2012, 21:42 69271

    Ανανέωση winform

    Καλησπέρα σε όλους

    Το πρόβλημα που έχω εμφανίζεται σε διάφορα σημεία στις εφαρμογές μου αλλά θα δώσω ένα απλό παράδειγμα.  Έχω μία winform με ένα button Και ένα progressbar.  Πατώντας το κουμπί ξενικάει μια διαδικασία που κάνει κάποιες μεταφορές data αρχείων μεταξύ δύο databases (sqlserver-odbc).  Η μεταφορά του κάθε αρχείου μπορεί να κρατήσει από μερικά δευτερόλεπτα έως αρκετά λεπτά, ανάλογα με το μέγεθος.  Θέλω λοιπόν να δείξω την πρόοδο με το progressbar.  Καταλαβαίνω ότι δεν μπορώ να έχω ανανέωση της φόρμας όσο γίνεται η κάθε μεταφορά, μια και γίνεται με μία εντολή (εκτός αν χρησιμοποιήσω async μεθόδους, αλλά γι αυτό θα περιμένω το επόμενο VS Smile ) αλλά, μια και μιλάμε για σχεδόν 30 αρχεία, τουλάχιστον να δείχνω πόσα αρχεία έχουν ολοκληρωθεί.  Κάνω λοιπόν το max του progressbar όσα είναι τα αρχεία και τρέχω το παρακάτω loop:

                    for (int f = 0; f < Tfiles.Rows.Count; f++)
                    {
                       \\  Εδώ είναι ο κώδικας που κάνει το transfer \\
                        this.progressBarTransfers.Value = f+1;
                        this.progressBarTransfers.Refresh();
                    }

    Πριν βάλω το Refresh() δεν έδειχνε τίποτα απολύτως στην φόρμα όσο προχώραγαν τα transfers, και μόνο όταν τελείωνε όλη η διαδικασία έδειχνε το progressbar γεμάτο.  Μετά το Refresh() δείχνει κανονικά, εκτός αν (όπως είναι φυσιολογικό όταν κάτι μπορεί να κρατήσει αρκετή ώρα σε σύνολο) κάποιος γυρίσει σε κάποια άλλη εφαρμογή (Excel, IE, οτιδήποτε), που σ' αυτή την περίπτωση η εφαρμογή εμφανίζει πλέον '(Not Responding)' στον τίτλο της και δεν κάνει καμιά ανανέωση στο progressbar μέχρι να τελειώσει όλη η διαδικασία, όπου και δείχνει το progressbar γεμάτο.  Αυτό ειναι πολύ εκνευριστικό γιατί αν θες κάποια στιγμή να γυρίσεις και να δεις σε ποιο στάδιο είναι η διαδικασία πλέον δεν μπορείς.  Τι μπορώ να κάνω για να μην συμπεριφέρεται έτσι;

    Ευχαριστώ πολύ

    Σεραφείμ

  •  13-02-2012, 04:40 69277 σε απάντηση της 69271

    Απ: Ανανέωση winform

    Το control που χρειάζεσαι είναι το BackgroundWorker.

  •  13-02-2012, 10:53 69284 σε απάντηση της 69277

    Απ: Ανανέωση winform

    George Parissis:

    Το control που χρειάζεσαι είναι το BackgroundWorker.



    Ευχαριστώ πολύ για την απάντηση.  Ήθελα να το αποφύγω αλλά... Το είδα λοιπόν, τροποποίησα την δομή του κώδικα, και παίζει μια χαρά.  Το νέο πρόβλημα που έχω τώρα λοιπόν είναι ότι πρέπει με κάποιο τρόπο να σταματήσω τον χρήστη από το να κάνει οτιδήποτε άλλο στην εφαρμογή μέχρι να τελειώσει η διαδικασία (να κλείσει την φόρμα-εφαρμογή, να μην πατάει κουμπιά, να μην αλλάζει tabs σε ένα tabcontrol που έχει πάνω η φόρμα κλπ).  Υπάρχει κάποιος εύκολος τρόπος να γίνει αυτό μαζικά ή πρέπει να ελέγχω στα πάντα ξεχωριστά αν τρέχει ο backgroundworker?

    Σεραφείμ
  •  13-02-2012, 11:31 69285 σε απάντηση της 69284

    Απ: Ανανέωση winform

    Γιατί να το αποφύγεις? Αν θέλεις κάποιες εργασίες να εκτελλούνται παράλληλα (γιατί αυτό θες, να δουλεύει και το UI και να γίνεται και processing), θα πρέπει να χρησιμοποιήσεις κάποιο μηχανισμό για παράλληλη επεξεργασίας. Το BackgroundWorker είναι η απλούστερη και πιο περιορισμένη μορφή, η οποία ταιριάζει "γάντι" σε αυτό που ζητάς.

    Όσο για το "να μην κάνει τίποτε άλλο", εδώ μιλάμε για το πως δουλεύει το UI. Καμμία σχέση με το πως γίνεται η επεξεργασία. Υπάρχουν πολλές λύσεις και το τί θα επιλέξεις εξαρτάται από το πως θέλεις να φαίνεται η εφαρμογή σου:

    • Μπορείς να εμφανίσεις ένα modal dialog box με το progressbar και ένα μήνυμα.  Είναι ίσως η πιο "κλασσική" υλοποίηση. Το μόνο που χρειάζεται είναι να φροντίσεις να κρύψεις το close button για να μην κλείσει κανείς τη φόρμα.
    • Αλλάζεις σε Enabled=False την κατάσταση των control που θέλεις να απενεργοποιήσεις όταν ξεκινάς και σε Enabled μόλις τελειώσεις την επεξεργασία. Αυτό είναι χρήσιμο όταν δεν θέλεις να μπορεί ο χρήστης να χρησιμοποιεί κάποια features της εφαρμογής, όχι όμως αυτά που ξεκινούν/σταματούν την επεξεργασία. Την πρόοδο μπορείς μετά να την παρουσιάσεις είτε με κάποιο modeless dialog box ή κάποιο progressbar ενσωματωμένο στη φόρμα σου.

    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  13-02-2012, 12:12 69288 σε απάντηση της 69285

    Απ: Ανανέωση winform

    Ο λόγος που ήθελα να το αποφύγω είναι γιατί κάποια πράγματα πρέπει να σχεδιαστούν με έναν πιο πολύπλοκο τρόπο.  Και εντάξει, δεν είναι μεγάλο το πρόβλημα, απλά αυτό το πάγωμα του UI επειδή αλλάζεις focused παράθυρο μου φάνηκε λίγο περίεργο και είπα μήπως υπάρχει κάποιος άλλος τρόπος λύσης.  Γιατί πρακτικά δεν θέλω να δουλεύουν δύο πράγματα ταυτόχρονα, να γίνεται refresh η φόρμα ενδιάμεσα από τα transfers θέλω.  Και αυτό γίνεται, εκτός αν αλλάξεις focused παράθυρο, οπότε παγώνουν όλα μέχρι να τελειώσουν όλα τα transfers.  Αυτή λοιπόν η συμπεριφορά μου φάνηκε λίγο περίεργη για να είναι κανονική.

    Ευχαριστώ και πάλι για την βοήθεια.

    Σεραφείμ
  •  13-02-2012, 12:34 69289 σε απάντηση της 69288

    Απ: Ανανέωση winform

    Δεν είναι περίεργη. Είναι η τυπική συμπεριφορά των desktop εφαρμογών από καταβολής GUI. Το UI τρέχει σε ένα thread. Αν το thread υπολογίζει, δεν μπορεί να γίνει ανανέωση ή επεξεργασία των μηνυμάτων που στέλνει το λειτουργικό στην εφαρμογή (π.χ. ζωγράφισμα περιοχής, κίνηση ποντικιού, κλικ, κλπ). Ακόμα και το ζωγράφισμα της οθόνης εκτελείται μόνο όταν το λειτουργικό στείλει το μήνυμα WM_DRAW. Όταν η εφαρμογή δεν ανταποκρίνεται στα μηνύματα, το λειτουργικό την παρουσιάζει ως Non Responsive - και αυτό ακριβώς συμβαίνει. 

    Μπορείς να προκαλέσεις την επεξεργασία των μηνυμάτων που έχουν μαζευτεί  με την Application.DoEvents, όχι την Refresh, αλλά και πάλι, αν η επεξεργασία κρατάει πολύ, το thread δεν μπορεί να ανανεώσει την οθόνη και να επεξεργαστεί τα μηνύματα. 
    Μπορείς να βασιστείς στην DoEvents μόνο αν η επεξεργασία κάθε ενός αρχείου κρατάει πολύ λίγο ώστε να μην προλάβει ο χρήστης να καταλάβει το μπλοκάρισμα. Φυσικά, όταν θα καλέσεις την DoEvents η εφαρμογή θα επεξεργαστεί ΚΑΙ τα click, close events τα οποία ήθελες να αποφύγεις.

    Είναι αρκετά πιο πολύπλοκο να προσπαθίσεις να τα κάνεις όλα αυτά με ένα μόνο thread σε σχέση με το να χρησιμοποιήσεις τo BackgroundWorker:
    • Στο κομμάτι της επεξεργασίας θα κάνεις ακριβώς τα ίδια - ή μάλλον λιγότερα - πράγματα. Αντί να καλείς την DoEvents θα καλείς την ReportProgress. 
    • Στο κομμάτι του UI, έτσι κι αλλιώς θα πρέπει να απενεργοποιήσεις εσύ με κάποιο τρόπο τα components που δεν θέλεις. Ο τρόπος που κάνεις την επεξεργασία δεν έχει σχέση και δεν επηρεάζει το μηχανισμό που θα επιλέξεις


    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  13-02-2012, 12:40 69290 σε απάντηση της 69289

    Απ: Ανανέωση winform

    Ήσουν κατατοπιστικότατος και πειστικότατος Smile.  Έχω κάνει ήδη τις αλλαγές.  Backgroundworker it is!

    Σεραφείμ
  •  16-02-2012, 13:10 69349 σε απάντηση της 69290

    Απ: Ανανέωση winform

    Συγνώμη, της τελευταίες ημέρες είχα να κάνω μετακόμιση. Γύρισα στα πάτρια εδάφη. Αποτέλεσμα της κατάστασης που επικρατεί και με το μέλλον αβέβαιο... Τέλος πάντων αυτό είναι μία άλλη συζήτηση.

    Από ότι βλέπω λύθηκε το θέμα με τον καλύτερο τρόπο.

Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems