0

ファイルをダウンロードする C# Windows アプリケーションを作成しようとしています (そのダウンロードが完了するのを待ちます - 進行状況のインジケーターを提供します)。ダウンロードしたファイルを実行します。私はどちらかが必要だと思います:

  • 進行状況インジケーターがあり、アプリケーションが応答しなくなることのない同期ダウンロード
  • ダウンロードが完了するのを待ってから実行を試みる非同期ダウンロード。

前者 (同期ダウンロード) は私が望むことをしているように見えますが、進行状況を示す方法が見つからず、プログラムが応答しなくなっているようです (ハングしたように) - ユーザーが代わりにアプリケーションを閉じる可能性がありますダウンロードが完了するのを待ちます。

後で(非同期ダウンロード)進行状況インジケーターなどで達成できましたが、ダウンロードが開始され、ダウンロードが完了する前にアプリケーションがすぐにインストールを試みますが、もちろん失敗します。

それで、これを達成するための最良の方法は何ですか?以下は、進行状況バー付きの非同期ダウンロード用に現在持っているコードです。

2012 年 4 月 10 日編集

古いコードは回避するのが面倒になってきていたので、ここに私が現在持っているものがあります。プログレスバーを更新しないことを除いて動作します。

    private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
    {

            List<App> FilesToDownload = e.Argument as List<App>;

            foreach (App Program in FilesToDownload) // Loop through List with foreach
            {
                //string Text = ;
                UpdateRichTextBox("Downloading " + Program.Filename + "... Please wait");

                string Source = Program.DownloadLocation + "/" +  Program.Filename;
                string Destination = System.AppDomain.CurrentDomain.BaseDirectory + Program.Filename;

                WebClient webClient = new WebClient();
                webClient.DownloadFile(Source, @Destination);
            }

            UpdateRichTextBox("File download complete");

            foreach (App Program in FilesToDownload) // Loop through List with foreach
            {
                string Filename = Program.Filename;
                string Arguments = Program.InstallParameters;

                if (Filename != "advisorinstaller.exe")
                {
                    Process p = new Process();
                    p.StartInfo.FileName = System.AppDomain.CurrentDomain.BaseDirectory + Filename;
                    p.StartInfo.Arguments = Arguments;
                    p.Start();
                    p.WaitForExit();
                }
                else
                {
                    MessageBox.Show("About to install Belarc Advisor. This may take 10-15 minutes to run - do not shutdown this program. Click OK when ready to proceed.");
                }
            }
    }

    private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
    {
        UpdateRichTextBox("Install Complete");

    }

2012 年 4 月 11 日を編集

したがって、バックグラウンドワーカーが次のように機能するように編集しました。

        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {

            List<App> FilesToDownload = e.Argument as List<App>;

            int counter = 0;
            int percent = 0;

            foreach (App Program in FilesToDownload) // Loop through List with foreach
            {
                percent = ((counter / FilesToDownload.Count) * 100);
                backgroundWorker1.ReportProgress(percent, "");

                UpdateRichTextBox("Downloading " + Program.Filename + "... Please wait");

                string Source = Program.DownloadLocation + "/" +  Program.Filename;
                string Destination = System.AppDomain.CurrentDomain.BaseDirectory + Program.Filename;

                WebClient webClient = new WebClient();
                webClient.DownloadFile(Source, @Destination);


                counter++;

            }

            //backgroundWorker1.ReportProgress(100, "Complete!");
    }

最後の行のコメントを外すと、プログレス バーは 100% に進みます。しかし、それを使用して進行していません:

percent = ((counter / FilesToDownload.Count) * 100);
backgroundWorker1.ReportProgress(percent, "");

理由はありますか?

4

4 に答える 4

1

を使用しBackgroundWorkerて、バックグラウンドで同期ダウンロードを実行できます。進捗レポートもサポートします。これにより、UIのブロックを回避できます(ダウンロードが別のスレッドで実行されているため)。

于 2012-04-04T18:57:49.410 に答える
0

ClickOnceを使用してこれを行うことを検討しましたか?自動更新とともに問題を解決します。

開始する場所については、このSOの質問を確認してください:https ://stackoverflow.com/questions/1635103/how-to-basic-tutorial-to-write-a-clickonce-app 。

于 2012-04-04T19:03:28.517 に答える
0

ManualResetEventクラスを使用して、(WaitOne() を使用して) client_DownloadFileCompleted() イベント ハンドラーが呼び出される (オブジェクトで Set() を呼び出す) まで、メイン スレッドで待機することができます。

于 2012-04-04T19:01:16.740 に答える
0

すでに非同期であるため (スレッドプールのスレッドを使用)、WebClientをラップする必要はありません。BackgroundWorker

注:以下のサンプルはエディターで作成されたものですが、MSDN のドキュメントでメソッド シグネチャを確認したところ、簡単に間違いを犯した可能性があります。

public void InstallSecuniaPSI()
{
    var source = new Uri("http://www.webserver.com:8014/psisetup.exe");
    var dest = Path.Combine(Path.GetTemp(), "Download_SecuniaPSI.exe");

    var client = new WebClient();
    client.DownloadProgressChanged += OnDownloadProgressChanged;
    client.DownloadFileCompleted += OnDownloadComplete;
    client.DownloadFileAsync(source, dest, dest);   
}

private void OnDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    // report progress
    Console.WriteLine("'{0}' downloaded {1} of {2} bytes. {3}% complete"(string)e.UserState, e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage);
}

private void OnDownloadComplete(object sender, AsyncCompletedEventArgs e)
{
    // clean up
    var client = (WebClient)sender;
    client.DownloadProgressChanged -= OnDownloadProgressChanged;
    client.DownloadFileCompleted -= OnDownloadComplete;

    if (e.Error != null)
        throw e.Error;

    if (e.Cancelled)
        Environment.Exit(1);

    // install program
    var downloadedFile = (string)e.UserState;
    var processInfo = new ProcessStartInfo(downloadedFile, "/S");
    processInfo.CreateNoWindow = true;

    var installProcess = Process.Start(processInfo);
    installProcess.WaitForExit();

    Environment.Exit(installProcess.ExitCode);
}

ここでソートする必要があるのは、プログラムを待機させる方法だけです。コンソール プログラムの場合はConsole.ReadKey()InstallSecuniaPSI().

HTH、

于 2012-04-04T22:37:41.833 に答える