Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 11
  1. #1

    [VB.NET] Applicazione multithreading WPF

    Ho la necessità di eseguire un ciclo nel quale vengono creati diversi oggetti Shape che devono essere aggiunti in un contenitore (Panel) per essere visualizzati all'interno dell'applicazione.

    Questo che segue è un esempio di ciò che devo fare:

    codice:
    For i = 0 To 200000
         Contenitore.Children.Add(New Rectangle)
    Next
    Essendo la quantità di oggetti creati notevole, ciò richiede diverso tempo in questo lasso di tempo l'applicazione è bloccata (l'interfaccia non risponde). Per risolvere questo problema solitamente facevo ricorso alla creazione di un nuovo Thread che si occupava della creazione e della gestione degli oggetti, o più semplicemente facendo ricorso al metodo asincrono BeginInvoke della classe Dispatcher. Tuttavia diversamente dalle mie precedenti esperienze questi metodi non sembrano funzionare, cosi come vengono usati, per risolvere il problema.

    codice:
    Contenitore.Dispatcher.BeginInvoke(DispatcherPriority.Normal, Sub() CreateObj())
    
    Private Sub  CreateObj()
    For i = 0 To 200000
         Contenitore.Children.Add(New Rectangle)
    Next
    End Sub
    La finestra dell'applicazione rimane sempre bloccata fino a quando la creazione di tutti gli elementi non viene completata.

    Come posso risolvere il problema? O meglio ancora anticipo il passaggio successivo, come fare in modo che (avendo l'applicazione non bloccata) gli oggetti vengano visualizzati immediatamente dopo essere stati aggiunti al contenitore senza aspettare che il metodo sia completato?

    Infatti fino a quando il metodo non è completo non viene visualizzato alcun elemento (ovviamente nell'applicazione vera gli oggetti hanno proprietà tali da poter essere visualizzati, come dimensioni, colore..)

    Grazie.
    Fracty - The Fractal Generator



    If you cannot choose a concise name that expresses what the method does, it is possible that your method is attempting to perform too many diverse tasks.

  2. #2
    Problema risolto! DoEvents

    Non mi rimane che cercare l'equivalente WPF
    Fracty - The Fractal Generator



    If you cannot choose a concise name that expresses what the method does, it is possible that your method is attempting to perform too many diverse tasks.

  3. #3
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,536

    Re: [VB.NET] Applicazione multithreading WPF

    ti basta anche un Thread.Sleep(1) dentro il ciclo :

    codice:
    Private Sub button1_Click(sender As Object, e As RoutedEventArgs)
    	Dim t As New Thread(AddressOf createObjec)
    	t.Start()
    End Sub
    
    Private Sub createObjec()
    	For i = 0 To 200000 'occhio che mi sembrano troppi!!!
    		Thread.Sleep(1)
    		Dispatcher.BeginInvoke(Function() Contenitore.Children.Add(New Rectangle()))
    	Next
    End Sub

  4. #4
    Purtroppo il metodo che hai proposto l'avevo già provato, mi da eccezione dopo pochi giri del ciclo: {"Impossibile accedere all'oggetto dal thread chiamante perché tale oggetto è di proprietà di un altro thread."}.

    Oltrettutto quella che credevo essere la soluzione, che ho riadattato per WPF utilizzando il dispatcher in questo modo:

    codice:
    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, Sub() Call EmptyDelegate())
    dove EmptyDelegate() è un metodo vuoto, funziona ma fino ad un certo punto. Nel senso che gli oggetti vengono immediatamente disegnati (probabilmente perchè il cambio di contesto permette a Windows di elaborare i messaggi di rendering), ma oltre al fatto che l'elaborazione risulta essere decisamente più lenta, ho notato facendo il debug che anche dopo essere uscito dal ciclo non sono stati visualizzati ancora tutti gli oggetti (e benche l'applicazione non sia completamente bloccata, lo risulta comunque essere parzialmente).

    In pratica sono al punti di partenza. Non riesco ad effettuare quel ciclo senza che l'applicazione si blocchi e in modo che gli oggetti vengano visualizzati subito dopo essere aggiunti al contenitore...

    Ps: purtroppo l'ordine di grandezza del numero di elementi e all'incirca quello..
    Come posso fare?
    Fracty - The Fractal Generator



    If you cannot choose a concise name that expresses what the method does, it is possible that your method is attempting to perform too many diverse tasks.

  5. #5
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,536
    Ciao

    Originariamente inviato da GliderKite
    Purtroppo il metodo che hai proposto l'avevo già provato, mi da eccezione dopo pochi giri del ciclo: {"Impossibile accedere all'oggetto dal thread chiamante perché tale oggetto è di proprietà di un altro thread."}.
    mmm, non lo vedo possibile un "invalid cross-thread access" nel modo che ho utilizzato nel post precedente

    Originariamente inviato da GliderKite
    Oltrettutto quella che credevo essere la soluzione, che ho riadattato per WPF utilizzando il dispatcher in questo modo:

    codice:
    Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, Sub() Call EmptyDelegate())
    dove EmptyDelegate() è un metodo vuoto, funziona ma fino ad un certo punto. Nel senso che gli oggetti vengono immediatamente disegnati (probabilmente perchè il cambio di contesto permette a Windows di elaborare i messaggi di rendering), ma oltre al fatto che l'elaborazione risulta essere decisamente più lenta, ho notato facendo il debug che anche dopo essere uscito dal ciclo non sono stati visualizzati ancora tutti gli oggetti (e benche l'applicazione non sia completamente bloccata, lo risulta comunque essere parzialmente).
    onestamente non mi sembra un buon metodo, ma ognuno ha le sue preferenze.

    Originariamente inviato da GliderKite
    In pratica sono al punti di partenza. Non riesco ad effettuare quel ciclo senza che l'applicazione si blocchi e in modo che gli oggetti vengano visualizzati subito dopo essere aggiunti al contenitore...
    ma la soluzione che ti ho postato l'hai provata nel tuo caso specifico? oppure hai dato per scontato che non funzionasse senza provarla? se è così (non l'hai provata) provala, non si sa mai

    Originariamente inviato da GliderKite
    Ps: purtroppo l'ordine di grandezza del numero di elementi e all'incirca quello..
    Come posso fare?
    prova descrivere meglio ciò che devi fare, magari un'altro modo si trova

  6. #6
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,536
    ti posto una classe completa che fa quello che vuoi tu, l'altro codice postato era più specifico per wp7 (credevo lavorassi su wp7 confondendomi con altro utente ), ma la sostanza non cambia : (tieni presente che sto modificando il codice da c# a vb)
    codice:
    Partial Public Class MainWindow
        Inherits Window
        Public Sub New()
            'this.DataContext = new MyViewModel();
            InitializeComponent()
        End Sub
    
        Private Sub button1_Click(sender As Object, e As RoutedEventArgs)
            Dim t As New System.Threading.Thread(AddressOf startThread)
            t.Start()
        End Sub
    
        Private Sub startThread()
            For i As Integer = 0 To 199999
                Dispatcher.Invoke(New Action(AddressOf createObjec), System.Windows.Threading.DispatcherPriority.Background)
            Next
        End Sub
        Private i As Integer = 0
        Private colore As New SolidColorBrush(Color.FromArgb(255, 0, 0, 0))
        Private Sub createObjec()
            Dim rect = New Rectangle()
            rect.Width = 10
            rect.Height = 10
            rect.Margin = New Thickness(5, 5 + 5 * i, 0, 0)
            rect.Fill = colore
            Me.grid.Children.Add(rect)
            i += 1
        End Sub
    End Class
    adesso vedo un pò come potresti migliorare le prestazioni per un numero così elevato di elementi.

  7. #7
    L'ho provata , sia quando l'avevo pensata per il mio progetto reale, sia quando ho creato un progetto di test che ora ti posto:

    codice:
    Imports System.Threading
    
    
    Class MainWindow
    
    
        Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
    
            Dim t As New Thread(AddressOf Me.CreateObj)
            t.SetApartmentState(ApartmentState.STA)
            t.Start()
    
        End Sub
    
    
        Private Sub CreateObj()
    
            Dim rect As Rectangle
    
            For i = 0 To 50000
                Thread.Sleep(1)
                rect = New Rectangle With {.Height = 200, .Width = 300, .Fill = New SolidColorBrush(Colors.Green)}
                Dispatcher.BeginInvoke(Sub() Me.TheGrid.Children.Add(rect))
            Next
    
        End Sub
    
    
    End Class
    E l'eccezione avviene dopo un po di giri nel ciclo...

    In ogni caso grazie per la disponibilità, appena posso provo la tua ultima risposta e ti faccio sapere
    Faccio notare che se non modifico l'appartment state in STA si verifica un'eccezione quando creo il rettangolo.
    Fracty - The Fractal Generator



    If you cannot choose a concise name that expresses what the method does, it is possible that your method is attempting to perform too many diverse tasks.

  8. #8
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,536
    Originariamente inviato da GliderKite
    L'ho provata , sia quando l'avevo pensata per il mio progetto reale, sia quando ho creato un progetto di test che ora ti posto:

    codice:
    Imports System.Threading
    
    
    Class MainWindow
    
    
        Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
    
            Dim t As New Thread(AddressOf Me.CreateObj)
            t.SetApartmentState(ApartmentState.STA)
            t.Start()
    
        End Sub
    
    
        Private Sub CreateObj()
    
            Dim rect As Rectangle
    
            For i = 0 To 50000
                Thread.Sleep(1)
                rect = New Rectangle With {.Height = 200, .Width = 300, .Fill = New SolidColorBrush(Colors.Green)}
                Dispatcher.BeginInvoke(Sub() Me.TheGrid.Children.Add(rect))
            Next
    
        End Sub
    
    
    End Class
    E l'eccezione avviene dopo un po di giri nel ciclo...

    In ogni caso grazie per la disponibilità, appena posso provo la tua ultima risposta e ti faccio sapere
    Faccio notare che se non modifico l'appartment state in STA si verifica un'eccezione quando creo il rettangolo.
    certo che così ti da problemi , devi creare il Rectangle nel Dispatcher...

    codice:
    Dispatcher.BeginInvoke(Sub() Me.grid.Children.Add(New Rectangle With {.Height = 200, .Width = 300, .Fill = New SolidColorBrush(Colors.Green)}))
    comunque usa l'ultimo metodo che ti ho postato, è molto meglio

  9. #9
    Si in effetti in questo modo c'è un cambiamento, tuttavia ottengo lo stesso effetto di quando utilizzavo il Dispatcher come ti avevo fatto vedere o la DoEvents. Credo che a questo punto il problema da affrontare stia nell'ottimizzazione del codice, dovro ricorrere al CLI.

    Fracty - The Fractal Generator



    If you cannot choose a concise name that expresses what the method does, it is possible that your method is attempting to perform too many diverse tasks.

  10. #10
    Utente di HTML.it L'avatar di U235
    Registrato dal
    Mar 2006
    Messaggi
    1,536
    Originariamente inviato da GliderKite
    Si in effetti in questo modo c'è un cambiamento, tuttavia ottengo lo stesso effetto di quando utilizzavo il Dispatcher come ti avevo fatto vedere o la DoEvents. Credo che a questo punto il problema da affrontare stia nell'ottimizzazione del codice, dovro ricorrere al CLI.



    cioè che effetto ottieni? cosa intendi per "parzialmente bloccata"? io ho provato quel codice, effettivamente ci mette un pò ad elaborare tutti gli elementi, ma li non puoi farci nulla però almeno non hai nessun blocco, potresti (come ho fatto io nel mio test) addirittura visualizzare il conteggio degli elementi già inseriti in tempo reale (texblock.Text = i) che si incrementa tipo cronometro e in più un button che se premuto esegue altre funzioni sempre in parallelo, e tutto senza avere nessun blocco, istantaneo!

    certo... prima di disegnare 200000 elementi... sono davvero tanti e vogliono il loro tempo... se consideri anche un solo millesimo di secondo ad elemento (esagerando in positivo) , ci vorrebbero più di 3 minuti...

    ma cosa devi farci con questa applicazione?

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.