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

 

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

Πρόβλημα με Async σε richTextBox

Îåêßíçóå áðü ôï ìÝëïò AlKiS. Τελευταία δημοσίευση από το μέλος Libra Storm στις 03-03-2012, 02:16. Υπάρχουν 19 απαντήσεις.
Σελίδα 2 από 2 (20 εγγραφές)   < 1 2
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  24-02-2012, 13:33 69436 σε απάντηση της 69435

    Απ: Πρόβλημα με Async σε richTextBox

    Μισό λεπτό για να καταλάβω... Κάνεις σύγκριση κατανομών; Αν ναι, δώσε ένα παράδειγμα με το είδος των αναζητήσεων που κάνεις. Πιθανόν το να σου έρχονται τα αποτελέσματα σε λίστα να είναι προτιμότερο από να χρωματίζεις το RTB.

    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  24-02-2012, 13:52 69437 σε απάντηση της 69431

    Απ: Πρόβλημα με Async σε richTextBox

    Αν κάτι χρειάζεται async είναι η ColoriseRTB. Αυτό όμως δεν γίνεται καθώς ο κώδικας έχει τα ίδια προβλήματα με τον προηγούμενο. Η ColoriseRTB εξακολουθεί να "πειράζει" τα controls οπότε απαιτείται Invoke. Επιπλέον, η Colorise κάνει δύο πράγματα, ψάχνει για λέξεις και αλλάζει τα controls. Αυτό είναι λάθος σχεδιασμός και ένα από τα αποτελέσματα του είναι ότι δεν μπορεί να εκτελεστεί ασύγχρονα.

    Τουλάχιστον αυτή η μέθοδος θα πρέπει να σπάσει στα δύο, μία SearchWords η οποία θα έχει ως παρεμέτρους τις γραμμές που πρέπει να αναζητηθούν και θα επιστρέφει τα locations, και μία colorize η οποία με βάση αυτή τη λίστα θα αλλάζει το χρώμα των λέξεων. Η SearchWords άνετα μπορεί να εκτελεστεί ασύγχρονα. Η Colorize όχι.

    Μπορούν να γίνουν και άλλες απλοποιήσεις, όπως πχ. να χρησιμοποιηθεί η RichTextBox.Select αντί για την αλλαγή των selection μέσω properties, για να μειωθούν οι καθυστερήσεις που οφείλονται στην επεξεργασία των αλλαγών των properties (π.χ. changed events, πιθανά redraws).

    Τέλος, αν ο αριθμός των λέξεων είναι μικρός μπορείς να χρησιμοποιήσεις pattern matching για να ψάξεις για όλες με μία κλήση της Matches, π.χ. Regex.Matches(input, "Word1|Word2|Word3"). 

    Μπορείς να φτιάξεις ένα function το οποίο θα φτιάχνει ένα pattern ενώνοντας όλες τις λέξεις με διαχωριστικό το '|' και θα επιστρέφει τα αποτελέσματα όπως παρακάτω:

        Function SearchWords(input As String, words As String()) As IEnumerable(Of Tuple(Of String, Integer, Integer))
            Dim pattern = String.Join("|", words)
            Dim matches = Regex.Matches(input, pattern)
            Dim indexes = From m As Match In matches
                          Select Tuple.Create(m.Value, m.Index, m.Length)
            Return indexes
        End Function

    Εδώ χρησιμοποιώ και λίγο LINQ για να επιστρέψω τα αποτελέσματα που θέλω χωρίς να φτιάξω ξεχωριστή κλάση

    Μετά μπορώ άνετα να κάνω αναζήτηση με μία μόνο κλήση, για όλες τις λέξεις όπως παρακάτω:

            Dim text = "This is some text I want to search. Try to find some words here"
            Dim search As String() = {"some", "to"}
    
            Dim results = SearchWords(text, search)
    
            For Each result In results
                Console.WriteLine("Found {0} at {1}:{2}", result.Item1, result.Item2, result.Item3)
            Next
            Console.ReadKey()





    Παναγιώτης Καναβός, Freelancer
    Twitter: http://www.twitter.com/pkanavos
  •  24-02-2012, 14:17 69438 σε απάντηση της 69437

    Απ: Πρόβλημα με Async σε richTextBox

    Πολύ ωραίο αυτό! 

    Μπορώ να ενοποιήσω λοιπόν όλα τα searches που έχω για το συγκεκριμένο rtb σε ένα και μόνο (αφού αυτά αλλάζουν τα ίδια χρώματα και bold στο κείμενο).

    Ευχαριστώ πολύ για τον κώδικα! Θα τον δω, θα τον προσαρμόσω στο πρόγραμμά μου, και κατόπιν θα κάνω πόστ το αποτέλεσμα.


    Μια τελευταία ερώτηση: Ποια εντολή είναι LINQ? (δυστυχώς δεν είχα χρόνο να διαβάσω για LINQ ακόμα, αλλά έχω σημειωμένο να το κάνω)


  •  24-02-2012, 14:56 69440 σε απάντηση της 69438

    Απ: Πρόβλημα με Async σε richTextBox

    Στο Function μου βγάζει πρόβλημα. Έκανα αλλαγή αλλά και πάλι δεν το παίρνει.

    1
    2
    3
    4
    5
    6
    7
    8
     
        Function SearchWords(input As String, words As String()) As IEnumerable(Of Tuple(Of String, Integer, Integer))
    
            Dim pattern As String = String.Join("|", words)
            Dim matches As System.Text.RegularExpressions.MatchCollection = Regex.Matches(input, pattern)
            Dim indexes = From m As Match In matches
                          Select Tuple.Create(m.Value, m.Index, m.Length)
            Return indexes
        End Function

    πρόβλημα: Error 1 Option Strict On disallows implicit conversions from 'Object' to 'System.Text.RegularExpressions.Match'. C:\Users\Giannis M\Dropbox\Visual Basic 2010\Projects\StatREC\StatREC\frmMain.vb 941 28 StatREC


    Ακόμα κι αν βάλω "Dim indexes As System.Text.RegularExpressions.Match = From m As Match In matches" πάλι το ίδιο μου λέει. Δεν καταλαβαίνω γιατί. 

    Χρηάζομαι επίσης επεξήγηση στα εξής:

    As IEnumerable, τι είναι αυτο???

    Of Tuple, Τι είναι αυτό? τη λέξη αυτή δεν την ξέρω καν στα αγγλικά.


  •  03-03-2012, 02:16 69531 σε απάντηση της 69440

    Απ: Πρόβλημα με Async σε richTextBox

    Δοκίμασε το παρακάτω και θα σου δουλέψει με Option strict on

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            Dim result As IEnumerable(Of Tuple(Of String, Integer, Integer))
    
            result = SearchWords("SELECT * FROM MyTable", New String() {"SELECT", "FROM"})
    
            For Each r As Tuple(Of String, Integer, Integer) In result
                Console.WriteLine("Value: {0} Index: {1} Length: {2}", r.Item1, r.Item2, r.Item3)
            Next
        End Sub
    
        Function SearchWords(input As String, words As String()) As IEnumerable(Of Tuple(Of String, Integer, Integer))
            Dim pattern As String = String.Join("|", words)
            Dim matches As MatchCollection = Regex.Matches(input, pattern)
    
            Dim indexes As IEnumerable(Of Tuple(Of String, Integer, Integer)) =
                From m As Match In matches.Cast(Of Match)()
                Select Tuple.Create(m.Value, m.Index, m.Length)
    
            Return indexes
        End Function

    Το IEnumerable είναι Interface. Το συγκεκριμένο Interface μας βοηθάει στο να μπορούμε να κάνουμε for each σε μία σειρά ή ακολουθία από αντικείμενα όπως  πχ τα controls μίας φόρμας ή τις γραμμές ενός Datatable. Στο συγκεκριμένο παράδειγμα δεν θα μπορούσα να κάνω for each αν το function δεν γύρναγε το Interface αυτό ή κάποιο άλλο class που να το περιέχει (ή πιό σωστά να το κάνει implements).

    Το tuple είναι μία δομή που μας βοηθάει να οργανώνουμε πληροφορίες σε μία "σειρά". ΠΧ αν θέλουμε να περάσουμε πολλά byref σαν παραμέτρους σε ένα function μπορούμε να το χρησιμοποιήσουμε. Επίσης σε περίπτωση που ένα function θέλουμε να γυρνάει πληροφορίες γιά κάτι, πχ τα στοιχεία ενός πελάτη (όνομα τηλέφωνο διεύθυνση κλπ) μπορούμε επίσης να το χρησιμοποιήσουμε. Το μοναδικό του "Μειονέκτημα" είναι ότι πρέπει να ξέρουμε τι πληροφορία πρέπει να βάλουμε στα στοιχεία του αφού αναφέρεται σε αυτά (όπως στο παράδειγμα) σαν item1, item2 κλπ.

    To μυστήριο μύνημα "exception has been thrown bla bla bla"  πάει να πει ότι λές σε κάποιον να κάτι, δεν τα καταφέρνει και αντί να σου πει γιατί δεν τα κατάφερε σου λέει απλά ότι δεν δεν τα κατάφερε... Παράδειγμα:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    Option Strict On
    Option Infer Off
    
    Imports System.Reflection
    
    Public Class Form1
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            Try
                Dim oResult As Object
                Dim div As New Division
    
                oResult = div.GetType.InvokeMember(
                    "Divide",
                    BindingFlags.InvokeMethod Or
                        BindingFlags.NonPublic Or
                        BindingFlags.Instance,
                    Type.DefaultBinder,
                    div,
                    {10, 0})
    
                MessageBox.Show(oResult.ToString)
            Catch ex As Exception
                If ex.InnerException IsNot Nothing Then
                    MessageBox.Show(ex.InnerException.ToString) ' Το exception που προκάλεσε το Invocation exception.
                End If
    
                MessageBox.Show(ex.ToString) ' Όλο το μύνημα.
            End Try
        End Sub
    End Class
    
    Public Class Division
        ' Μήπως παρατηρείς τίποτα "παράξενο"
        ' εδώ;
        Private _
        Function Divide(x As Integer, y As Integer) As Integer
            Return x \ y
        End Function
    End Class

    Το inner Exception στο παράδειγμα σου λέει τι πραγματικά συνέβη.

    Όσον αφορά την περίπτωση που εσύ λες ότι μπoρεί κάποιος να έχει ένα σενάριο 12000000 γραμμών σε ένα RichTextBox, μπορεί σε κάποιο μηχάνημα να δουλεύει αλλά στο δικό μου θα βγει το CPU από το τροφοδοτικό (μαζί με τις μνήμες).
    ϊσως θα μπορούσες να γράψεις το κατεβατό σε αρχείο και να το διαβάζεις κομμάτι κομμάτι κάνωντας και τις αλλαγές στα χρώματα, έτσι θα κερδίσεις και μνήμη και ταχύτητα. Υπάρχει ένα μεγάλο πρόβλημα με το richtextbox βέβαια, το ότι δεν ξέρεις την τιμή που έχει το Scrollbar ή την θέση του cursor γιά να προφορτώσεις τις επόμενες σελίδες και  η ταχύτητα που μπορεί κάποιος να το ανεβοκατεβαζει να είναι τόσο μεγάλη, που να μην μπορείς να διαβάσεις γρήγορα το αρχείο και να δείξεις το τμήμα που αντιστοιχεί στην συγκεκριμένη θέση. Δεν μου έχει τύχει παρόμοια περίπτωση με τόσο μεγάλα αρχεία γιά να είμαι ειλικρινής.

    Το async και το await είναι βολικά αλλά και τα Task από μόνα τους δεν είναι δύσχρηστα. Το παρακάτω παράδειγμα σου λέει πως να φτιάξεις ένα class το οποίο εκτελεί ένα Sub και μόλις τελειώσει σου στέλνει ένα event. Η νοοτροπία του να βάζουμε τέτοιες διαδικασίες σε classes είναι πολύ καλή κατά την γνώμη μου. Καλά είναι και τα Async await αλλά φοβάμαι ότι η αλόγιστη χρήση τους μπορεί ναι οδηγήσει σε δυσανάγνωστο κώδικα.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
     
    Option Strict On
    Option Infer Off
    
    Imports System.Threading.Tasks
    
    Public Class Form1
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            Try
                Me.Text = "Start"
                Dim t As New NotifyTask(AddressOf DoSomething, AddressOf TaskFinished)
    
                Me.Button1.Enabled = False
            Catch ex As Exception
                MessageBox.Show(ex.ToString)
            End Try
        End Sub
    
        Private Sub DoSomething()
            Threading.Thread.Sleep(3000)
        End Sub
    
        Private Sub TaskFinished(sender As System.Object, e As System.EventArgs)
            Try
                Me.Text = "Done"
                Me.Button1.Enabled = True ' Δεν χρειάζεται να κάνεις invoke δες παρακάτω γιατί.
            Catch ex As Exception
                MessageBox.Show(ex.ToString)
            End Try
        End Sub
    End Class
    
    ' -------------------------------------------------------------------------------------
    
    Public Class NotifyTask
        ' Θα μπορούσες να κληρονομήσεις το EventArgs και να φτιάξεις δικό σου, 
        ' π.χ. TaskEventArgs γιά να σου γυρίζει και το Task με τα όποια λάθη έχει και, 
        ' να το περάσεις σαν παράμετρο στην WhenFinished As EventHandler(Of TaskEventArgs).
        Public Sub New(SubToCall As Action, WhenFinished As EventHandler(Of EventArgs))
            Try
                If SubToCall Is Nothing Then Throw New ArgumentNullException("SubToCall")
    
                AddHandler Me.TaskEnd, WhenFinished
    
                Task.Factory.StartNew(SubToCall).
                    ContinueWith(AddressOf EndTask, TaskScheduler.FromCurrentSynchronizationContext)
    
                ' Αν σε δυσκολεύει η παραπάνω σύνταξη δες αυτήν.
                ''Dim tsk As Task = Task.Factory.StartNew(SubToCall)
                ''Dim tsk2 As Task = tsk.ContinueWith(AddressOf EndTask, TaskScheduler.FromCurrentSynchronizationContext)
    
                ' Οι παραπάνω 2 γραμμές λένε:
                ' 1. Ξεκίνα ένα task που θα τρέξει σε νέο thread και
                ' 2. μόλις τελειώσει, συνέχισε (ContinueWith) με ένα άλλο Task που θα τρέξει στο thread από το οποίο φτιάχτηκε το Class NotifyTask.
                '    (Στην δική μας περίπτωση στο κυρίως Thread).
    
                ' Γιά αυτόν τον λόγο βάλαμε το "μυστήριο" TaskScheduler.FromCurrentSynchronizationContext σαν παράμετρο στο 2ο Task.
                ' Με αυτόν τον τρόπο όταν κληθεί το Sub TaskFinished από το TaskEnd event, δεν χρειάζεται να κάνεις Me.InvokeRequired και invoke,
                ' γιατί θα τρέξει στο thread που φτιάξαμε το UI (User Interface).
            Catch
                Throw
            End Try
        End Sub
    
        Private Event TaskEnd As EventHandler(Of EventArgs)
    
        Private Sub EndTask(ByVal task As Task)
            RaiseEvent TaskEnd(Me, New EventArgs)
        End Sub
    End Class

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