Hirdetés

Új hozzászólás Aktív témák

  • joysefke

    veterán

    WPF
    A letöltés szépen működik meg minden, de belefutottam egy problémába, amit nem tudtam megoldani:
    szeretném, ha az összes párhuzamos letöltés állapota egy progress csíkon aggregáltan látszódna, tehát letöltött bájtok/összes letöltendő bájt.

    Na ezt nem tudom megoldani, nem értem, hogy hol a hiba. Attól eltekintve, hogy már ránézésre is ronda. Már többször átstrukturáltam a releváns kódrészletet, de nem akarja az igazságot, a letöltések szépen működnek, de a progress bar nem moccan. debuggolni sem igazán tudom...

    A kód:
    MainWindow.xaml.cs

    Miután a user kiválasztotta, hogy mit akar letölteni, kreálok egy progress objektumot (ez fogja a teljes letöltés állapotát mutatni) és ezt illetve a cél könyvtárat átadom a _session objektum letöltő metódusának. Ez a metódus minden fájlt egy egy Task-async művelettel tölt le, amelyek egy-egy Progress<double> objektumon keresztül tudják állapotukat visszajelezni. Ezeknek az egyes Progress<double>-oknak a visszajelzéseit szeretném egyetlen egy Progress<double>-ba aggregálni. Na ez nem megy.

    private async void _downloadAudios(object sender, RoutedEventArgs e)
    {
    ...
    IProgress<double> [B]progress[/B] = [B]new Progress<double>[/B]([B]a =>[/B] _fileProgressBar.[B]Value = a*100[/B]);
    [B]await _session.DownloadAudioAsync(_folderPath, progress);[/B]
    }

    Másik fájl
    DownloadAudiosAsync:

    public async Task DownloadAudioAsync(string downloadPath, IProgress<double> progress)

    ....
    List<Task> dlTasks = new List<Task>();


    [B]Itt fogom az egyes fájlok teljes méretét illetve az aktuálisan letöltött
    bájt-számokat tárolni. Ezek az adatok az aggregáláshoz kellenek.
    [/B] Az összes Action<double> delegate hozzáfér ezekhez és ugyanazt látják.

    //[B]long[] bytesDownloaded[/B] = new long[_videoDisplayInfos.Count];
    //[B]long[] fileSizes[/B] = new long[_videoDisplayInfos.Count];

    //Előre előkészítem a Progress objektumoknak az üres helyet. Az első
    tömb fogja a valós, a második pedig a dummy (null) Progress objektumokat
    tartalmazni. Indokás később

    [B]IProgress<double>[] fileDLprogresses [/B]= new IProgress<double>[_videoDisplayInfos.Count];
    [B]IProgress<double>[] progressesEmpty [/B]= new IProgress<double>[_videoDisplayInfos.Count];

    [B]A dummy tömböt feltöltöm csupa Progress = null referenciával[/B].
    Indoklás később.

    for (int i=0; i< progressesEmpty.Length; ++i) progressesEmpty[i] = new Progress<double>();

    //összes fájl együttes mérete tárolódik itt
    long totalBytesToDownload = 0;



    [B]//Ezen a for cikluson belül lesznek megkreálva az egyes Action delegate-k,
    melyek elkapják a ciklusváltozót és lemásolják azt. Illetve itt lesznek az
    egyes Task-async letöltések elindítva.[/B]

    //végigmegyünk a letöltendő videókon
    for (int i=0; i < _videoDisplayInfos.Count; ++i)
    {

    //letöltendő videók letöltésre kijelölt streamjeinek adatait kiszedjük
    VideoDisplayInfo videoDisplayInfo2 = _videoDisplayInfos[i];
    AudioStreamInfo streamToDownload2=_videoDisplayInfos[i].PreferredAudioStream;

    //csak ha létezik a videóhoz megfelelő stream
    if (streamToDownload2 != null)

    //fájladatokat (név, útvonal, kiterjesztés) kiszedem/legyártom
    string fileExtension2 = streamToDownload2.Container.GetFileExtension();
    string sanitizedFileName2 = Utils.SanitizeFilename(videoDisplayInfo2.Title);
    string filename2 = Path.ChangeExtension(Path.Combine(downloadPath, sanitizedFileName2), fileExtension2);

    //fájlok méretadatait elmentem
    fileSizes[i] = streamToDownload2.Size;
    totalBytesToDownload += fileSizes[i];


    [B]//Megkreálom az egyes Progress<double> objektumok action delegate-ját.[/B]
    //Minden delegate updatelgeti az őt futtató letöltés által letöltött adatmennyiséget
    //Majd meghívja az aggregált delegatet
    //
    Action<double> action = value =>
    {
    // captured loop iterator
    int index = i;
    long fileSize = fileSizes[index];
    long totalBytesDownloaded;
    lock (bytesDownloaded)
    {
    long oldValue = bytesDownloaded[index];
    bytesDownloaded[index] = (long)(value * fileSize);
    totalBytesDownloaded = bytesDownloaded.Sum();
    progress.Report(totalBytesDownloaded / totalBytesToDownload);
    }
    };

    //megkreálom a valós Progress objektumokat
    fileDLprogresses[i] = new Progress<double>(action);

    //Elindítom a letöltéseket a dummy (null) Progress objektumokkal.

    dlTasks.Add(_youtubeClient.DownloadMediaStreamAsync(streamToDownload2, filename2, progressesEmpty[i]));

    [B]//if blokk vége[/B]
    }

    [B]//for blokk vége[/B]
    }

    // Miután kiléptem a for ciklusból és az int i ciklusváltozó érvényét vesztette lecserélem
    a dummy Progress referenciákat az igazi Progress referenciákra. A for cikluson belül
    nem lehet odaadni az igazi Progress referenciákat, mert az Action delegateben
    a ciklusváltozó akkor még érvényes.

    for (int j = 0; j < progressesEmpty.Length; ++j) progressesEmpty[j] = fileDLprogresses[j];

    // bevárom a letöltést
    await Task.WhenAll(dlTasks);

    }

Új hozzászólás Aktív témák