IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

[WPF] Gérer le 'DownloadCompleted' d'un bitmap chargé depuis BackgroundWorker


Sujet :

VB.NET

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    158
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 158
    Points : 41
    Points
    41
    Par défaut [WPF] Gérer le 'DownloadCompleted' d'un bitmap chargé depuis BackgroundWorker
    Bonjour,

    Dans mon programme j'ai un BackgroundWorker qui lance, par l'intermédiaire de plusieurs Sub, le téléchargement, le redimensionnement et le formatage en .png d'images.
    Je peux voir que tout le cheminement suit son cours, jusqu'au Sub SaveImage() où manifestement le handler pour 'bitmap.DownloadCompleted' n'est pas pris en compte!?
    Pourriez-vous svp me dire la raison de ceci..et comment -en gardant la structure actuelle de division des taches par plusieurs Subs- je pourrais arriver à ce que les images soient correctement sauvées!?

    D’avance un grand merci!!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    Imports System.ComponentModel
    Imports System.IO
    Imports System.Net
     
    Class MainWindow
        Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
            Dim but As Button = TryCast(sender, Button)
            ProgressBar1.Value = 0
            Dim worker As BackgroundWorker = New BackgroundWorker() With {.WorkerReportsProgress = True, .WorkerSupportsCancellation = True}
            AddHandler worker.DoWork, New DoWorkEventHandler(AddressOf worker_DoWork)
            AddHandler worker.ProgressChanged, New ProgressChangedEventHandler(AddressOf worker_ProgressChanged)
            AddHandler worker.RunWorkerCompleted, New RunWorkerCompletedEventHandler(AddressOf worker_RunWorkerCompleted)
     
            worker.RunWorkerAsync()
            worker.Dispose()
        End Sub
        Sub worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
            Dim dataItemsList As New List(Of String)
            dataItemsList.Add("jntCA3d.jpg")
            dataItemsList.Add("nRVcjd6.jpg")
            dataItemsList.Add("b4PDGb8.jpg")
     
            Dim filePath As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
            filePath = filePath & "\Test\"
            If Not Directory.Exists(filePath) Then
                Directory.CreateDirectory(filePath)
            End If
     
            Dim ProgressPercentage As Integer = 0
            ProgressPercentage = 0
            For Each str As String In dataItemsList
                collectInfoGB(str, filePath)
                ProgressPercentage += 1
                TryCast(sender, BackgroundWorker).ReportProgress(ProgressPercentage, dataItemsList.Count)
            Next
        End Sub
        Private Sub collectInfoGB(ByVal str As String, ByVal path As String)
            Dim fullUrl = "http://i.imgur.com/" & str
            Try
                Dim requ As WebRequest = WebRequest.Create(fullUrl)
                requ.Timeout = 5000
                Dim response As WebResponse = requ.GetResponse()
                Dim stream As Stream = response.GetResponseStream()
     
                If Directory.Exists(path) Then
                    Dim bitmap As New BitmapImage()
                    bitmap.BeginInit()
                    bitmap.UriSource = New Uri(fullUrl)
                    bitmap.EndInit()
                    '
                    SaveImage(bitmap, str, path)
                End If
            Catch webError As WebException
                If webError.Status = WebExceptionStatus.Timeout Then
                    Debug.Print("TimeOut exception")
                End If
            End Try
        End Sub
        Sub SaveImage(ByVal bitmap As BitmapImage, ByVal str As String, ByVal path As String)
            Debug.Print("passed")
            If bitmap.IsDownloading Then
                AddHandler bitmap.DownloadCompleted, New EventHandler(Sub(sender As Object, args As EventArgs) processImage(bitmap, str, path))
            Else
                processImage(bitmap, str, path)
            End If
        End Sub
        Sub processImage(ByVal bitmap As BitmapImage, ByVal str As String, ByVal path As String) ' Limit to 640px
            Dim ratio As Decimal = 1
            Dim maxSize As Integer = 640
            Dim width As Integer = bitmap.PixelWidth
            Dim height As Integer = bitmap.PixelHeight
            If Math.Max(width, height) > maxSize Then
                ratio = maxSize / Math.Max(width, height)
            End If
            '
            Dim tbBitmap As New TransformedBitmap(bitmap, New ScaleTransform(ratio, ratio, 0, 0))
            Dim encoder As PngBitmapEncoder = New PngBitmapEncoder()
            encoder.Frames.Add(BitmapFrame.Create(tbBitmap))
            Using filestream = New FileStream(path & "\" & str & ".png", FileMode.Create)
                encoder.Save(filestream)
            End Using
        End Sub
        Private Sub worker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
            If e.UserState IsNot Nothing Then
                ProgressBar1.Value = CDbl(e.ProgressPercentage / e.UserState * 100)
            End If
        End Sub
        Private Sub worker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
            '
        End Sub
    End Class
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Button Content="Start" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="Button1" VerticalAlignment="Top" Width="75" />
            <ProgressBar Height="19" HorizontalAlignment="Left" Margin="12,146,0,0" Name="ProgressBar1" VerticalAlignment="Top" Width="479" />
        </Grid>
    </Window>

  2. #2
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Bonsoir,

    Il y a une chose qui manifestement n'est pas correctement gérée lorsque tu souhaites sauvegarder les 3 images exemples !

    - Tes 3 images portent l'extension ".jpg", tu instancies un objet de type Bitmap pour stocker l'image, tu enregistres avec un encoder PNG

    Ça fait beaucoup de manipulation de format qui à mon humble avis ne t'apporte pas le résultat escompté.


    Ensuite, dans ta Sub CollectInfosGB, tu utilises une Webrequest qui finalement n'aboutit pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
      Dim requ As WebRequest = WebRequest.Create(fullUrl)
                requ.Timeout = 5000
                Dim response As WebResponse = requ.GetResponse()
                Dim stream As Stream = response.GetResponseStream()
    Je pense qu'il faudrait au contraire utiliser cette webrequest pour télécharger ton image, puis dans le Header de ta webrequest tu pourrais récupérer le Content-Type et le Content-Lenght. Ainsi tu pourrais sauvegarder ton image en utilisant cette méthode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
       Dim wReq As HttpWebRequest = DirectCast(WebRequest.Create("http://www.imabox.fr/15/10/021838e7hLsm30.png"), HttpWebRequest)
                Dim wResp As HttpWebResponse = DirectCast(wReq.GetResponse(), HttpWebResponse)
                Dim Length = wResp.Headers.Item("Content-Length").ToString
                Dim mimeType = wResp.Headers.Item("Content-Type").ToString
                If Not Length = 0 AndAlso mimeType.StartsWith("image") Then
                    Dim img = System.Drawing.Image.FromStream(wResp.GetResponseStream)
                    If Not img Is Nothing Then
                        Select Case mimeType
                            Case "image/png"
                                img.Save("D:\f.png", Imaging.ImageFormat.Png)
                            Case "image/jpeg", "image/jpg", "image/jpe"
                                img.Save("D:\f.png", Imaging.ImageFormat.Jpeg)
                            Case "image/gif"
                                img.Save("D:\f.png", Imaging.ImageFormat.Gif)
                            Case "image/bmp"
                                img.Save("D:\f.png", Imaging.ImageFormat.Bmp)
                        End Select
                    End If
                End If
    et tu pourrais oublier cette manipulation de sauvegarde d'image :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
       If Directory.Exists(path) Then
                    Dim bitmap As New BitmapImage()
                    bitmap.BeginInit()
                    bitmap.UriSource = New Uri(fullUrl)
                    bitmap.EndInit()
                    '
                    SaveImage(bitmap, str, path)
                End If
    Enfin je ne pourrais te recommander de faire un tour ici car le téléchargement de fichiers par lot y est très bien illustré et commenté :

    http://3dotdevcoder.blogspot.fr/2015...s-en-file.html

    A+

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    158
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 158
    Points : 41
    Points
    41
    Par défaut
    Merci pour ta réponse, je vais l'étudier attentivement, mais elle ne correspond pas directement à mon interrogation:
    pourquoi dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    AddHandler bitmap.DownloadCompleted, New EventHandler(Sub(sender As Object, args As EventArgs) processImage(bitmap, str, path))
    le sub 'processImage' n'est jamais appelé!!

    La structure actuelle, même si imparfaite et optimisable, marche très bien si utilisée sans BackgroundWorker.
    Je voudrais donc savoir où cela 'cloche' quand utilisée avec un BackgroundWorker!

    Merci,

  4. #4
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Citation Envoyé par Jayme65 Voir le message
    La structure actuelle, même si imparfaite et optimisable, marche très bien si utilisée sans BackgroundWorker.
    Je voudrais donc savoir où cela 'cloche' quand utilisée avec un BackgroundWorker!

    Merci,
    Bonjour,

    Tout simplement parce que tes 2 threads ne sont pas synchronisés ! (OUI le téléchargement de ton BitmapImage est considéré comme un thread de type asynhrone).
    Si tu ajoutes une temporisation dans ta sub SaveImage alors tes images seront correctement enregistrées :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     Sub SaveImage(ByVal bitmap As BitmapImage, ByVal str As String, ByVal path As String)
            'Le msgbox est considéré comme une temporisation. Attention le thread.Sleep n'aura aucun impact et cause souvent problème dans un thread Async (Freeze UI,...etc....) !!!!
            Msgbox("Breaking ...")
            If bitmap.IsDownloading Then
                AddHandler bitmap.DownloadCompleted, New EventHandler(Sub(sender As Object, args As EventArgs) processImage(bitmap, str, path))
            Else
                processImage(bitmap, str, path)
            End If
        End Sub
    C'est pour cela qu'il faut simplifier ce purin en utilisant comme évoqué plus haut la WebRequest qui est de type Synchrone ou la classe WebClient en utilisant la méthode "DownloadFile" qui elle aussi est synchrone :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
      If Directory.Exists(path) Then
                    using wc As New WebClient
                        wc.DownloadFile(fullUrl, path & "\" & str)
                    End Using
                End If
    ou alors en définitive mettre en place un thread pool si tu veux vraiment rester sur ta problématique !

    Pour moi la meilleure alternative étant d'utiliser la webrequest, ainsi tu pourras convertir dans le thread du BGW le stream vers un autre type de fichier (comme évoquée dans mon précédent message).

    A+

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    158
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2006
    Messages : 158
    Points : 41
    Points
    41
    Par défaut
    Merci à nouveau pour ta réponse, je comprends mieux maintenant (je pense ;-) )grâce à ton explication sur le traitement synchrone/asynchrone!
    Voici donc une version fonctionelle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    Imports System.ComponentModel
    Imports System.IO
    Imports System.Net
    Imports System.Windows.Threading
    Class MainWindow
        Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
            Dim but As Button = TryCast(sender, Button)
            ProgressBar1.Value = 0
            Dim worker As BackgroundWorker = New BackgroundWorker() With {.WorkerReportsProgress = True, .WorkerSupportsCancellation = True}
            AddHandler worker.DoWork, New DoWorkEventHandler(AddressOf worker_DoWork)
            AddHandler worker.ProgressChanged, New ProgressChangedEventHandler(AddressOf worker_ProgressChanged)
            AddHandler worker.RunWorkerCompleted, New RunWorkerCompletedEventHandler(AddressOf worker_RunWorkerCompleted)
            worker.RunWorkerAsync()
            worker.Dispose()
        End Sub
        Sub worker_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
            Dim dataItemsList As New List(Of String)
            dataItemsList.Add("jntCA3d.jpg")
            dataItemsList.Add("nRVcjd6.jpg")
            dataItemsList.Add("b4PDGb8.jpg")
     
            Dim filePath As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
            filePath = filePath & "\Test\"
            If Not Directory.Exists(filePath) Then
                Directory.CreateDirectory(filePath)
            End If
     
            Dim ProgressPercentage As Integer = 0
            ProgressPercentage = 0
            For Each str As String In dataItemsList
                collectInfoGB(str, filePath)
                ProgressPercentage += 1
                TryCast(sender, BackgroundWorker).ReportProgress(ProgressPercentage, dataItemsList.Count)
            Next
        End Sub
        Private Sub collectInfoGB(ByVal str As String, ByVal path As String)
            Dim fullUrl = "http://i.imgur.com/" & str
            Try
                If Directory.Exists(path) Then
                    Dim bitmap As New BitmapImage()
                    Dim buffer = New WebClient().DownloadData(fullUrl)
                    Using stream = New MemoryStream(buffer)
                        bitmap.BeginInit()
                        bitmap.CacheOption = BitmapCacheOption.OnLoad
                        bitmap.StreamSource = stream
                        bitmap.EndInit()
                    End Using
                    '
                    SaveImage(bitmap, str, path)
                End If
            Catch webError As WebException
                If webError.Status = WebExceptionStatus.Timeout Then
                    Debug.Print("TimeOut exception")
                End If
            End Try
        End Sub
        Sub SaveImage(ByVal bitmap As BitmapImage, ByVal str As String, ByVal path As String)
            If bitmap.IsDownloading Then
                AddHandler bitmap.DownloadCompleted, New EventHandler(Sub(sender As Object, args As EventArgs) processImage(bitmap, str, path))
            Else
                processImage(bitmap, str, path)
            End If
        End Sub
        Sub processImage(ByVal bitmap As BitmapImage, ByVal str As String, ByVal path As String) ' Limit to 640px
            Dim ratio As Decimal = 1
            Dim maxSize As Integer = 640
            Dim width As Integer = bitmap.PixelWidth
            Dim height As Integer = bitmap.PixelHeight
            If Math.Max(width, height) > maxSize Then
                ratio = maxSize / Math.Max(width, height)
            End If
            '
            Dim tbBitmap As New TransformedBitmap(bitmap, New ScaleTransform(ratio, ratio, 0, 0))
            Dim encoder As PngBitmapEncoder = New PngBitmapEncoder()
            encoder.Frames.Add(BitmapFrame.Create(tbBitmap))
            Using filestream = New FileStream(path & "\" & str & ".png", FileMode.Create)
                encoder.Save(filestream)
            End Using
        End Sub
        Private Sub worker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
            If e.UserState IsNot Nothing Then
                ProgressBar1.Value = CDbl(e.ProgressPercentage / e.UserState * 100)
            End If
        End Sub
        Private Sub worker_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
            '
        End Sub
    End Class
    Je voudrais bien essayer avec un WebRequest (notamment pour tirer parti de la gestion du TimeOut)...mais malgré toute ma bonne volonté et mes essais répétés je n'arrive pas à l'implanter et que cela fonctionne.
    Donc, puis je une dernière fois faire appel à ta générosité et te demander ce que cela donnerait avec un WebRequest?
    Cela concerne donc cette partie, comment puis-je stp utiliser un WebRequest et avoir au final un BitmapImage (obligé car je suis en WPF) que je peux envoyer au Sub qui s'occupe du resize:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Dim bitmap As New BitmapImage()
         Dim buffer = New WebClient().DownloadData(fullUrl)
         Using stream = New MemoryStream(buffer)
             bitmap.BeginInit()
             bitmap.CacheOption = BitmapCacheOption.OnLoad
             bitmap.StreamSource = stream
             bitmap.EndInit()
    End Using
    Merci!!

  6. #6
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Bonsoir,

    Je pense que tu devrais parcourir ce sujet :

    http://stackoverflow.com/questions/5...-thread-in-wpf

    Personnellement avec cet exemple j'ai réussi à implémenter le téléchargement en file d'attente avec redimensionnement sans que l'application ne gèle durant les opérations.

    Si tu peines vraiment je verrais pour te mettre sur la bonne piste.

    Il faut persévérer. Bon courage.

    A+

Discussions similaires

  1. [VB.NET][WPF] Gérer l'audio avec 'MediaPlayer'
    Par Jayme65 dans le forum Windows Presentation Foundation
    Réponses: 9
    Dernier message: 17/01/2012, 23h25
  2. Réponses: 2
    Dernier message: 10/09/2009, 18h54
  3. "/etc" chargé depuis CLE usb
    Par Papipen dans le forum Ubuntu
    Réponses: 0
    Dernier message: 16/05/2008, 11h08
  4. Validateur d'objets chargé depuis un XML
    Par mister3957 dans le forum XML
    Réponses: 2
    Dernier message: 10/05/2007, 18h54
  5. [classpath]classpath non chargé depuis le jar, le système,..
    Par Grummfy dans le forum Général Java
    Réponses: 5
    Dernier message: 12/01/2006, 17h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo