2017-11-19 8 views
0

Visual StudioでWPFアプリケーションを作成しています。大きなファイルをダウンロードしてコードで抽出する必要があります。誰かが私がバックグラウンドワーカーを使うことを勧めましたが、現在進行状況バーの値を上げようとするとうまくいきません...だれでも助けてくれますか?UIが応答しない+バックグラウンドワーカーを使用中にプログレスバーが機能しないC#

public void InstallVersion(string version) 
    { 
     string location = File.ReadAllText(@"C:\Users\" + Environment.UserName + @"\AppData\Roaming\MidnightFallsLauncher\data\locator.txt"); 
     location = location + @"\Versions\" + version; 

     if (File.Exists(location + ".zip")) 
      File.Delete(location + ".zip"); 

     if (Directory.Exists(location)) 
     { 
      DirectoryInfo di = new DirectoryInfo(location); 

      foreach (FileInfo file in di.GetFiles()) 
      { 
       file.Delete(); 
      } 
      foreach (DirectoryInfo dir in di.GetDirectories()) 
      { 
       dir.Delete(true); 
      } 
     } 


     if (!myWorker.IsBusy) 
     { 
      myWorker.RunWorkerAsync(); 
     } 
    } 

そして、ここでは私の労働者が実行している間、UIがフリーズ...私はそれが起こることを意図していないかなり確信している、また、私のワーカーコード

public MainWindow() 
    { 
     InitializeComponent(); 

     myWorker.DoWork += new DoWorkEventHandler(myWorker_DoWork); 
     myWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(myWorker_RunWorkerCompleted); 
     myWorker.ProgressChanged += new ProgressChangedEventHandler(myWorker_ProgressChanged); 
     myWorker.WorkerReportsProgress = true; 
     myWorker.WorkerSupportsCancellation = true; 
    } 

    protected void myWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 

     string location = File.ReadAllText(@"C:\Users\" + Environment.UserName + @"\AppData\Roaming\MidnightFallsLauncher\data\locator.txt"); 
     location = location + @"\Versions\" + Version; 

     WebClient Client = new WebClient(); 
     string url = ""; 
     string content = ""; 
     string downloadlink = ""; 

     List<string> availibleVersions = new List<string>(); 
     List<string> versionDownload = new List<string>(); 

     url = "https://midnightfalls.glitch.me/versions.html"; 
     content = Client.DownloadString(url); 

     foreach (string line in content.Split(new string[] { "<br>", "<br />" }, StringSplitOptions.None)) 
     { 
      if (line.Contains("0")) 
      { 
       availibleVersions.Add(line); 
      } 

     } 

     url = "https://midnightfalls.glitch.me/versionslink.html"; 
     content = Client.DownloadString(url); 

     foreach (string line in content.Split(new string[] { "<br>", "<br />" }, StringSplitOptions.None)) 
     { 
      if (line.Contains("https")) 
      { 
       versionDownload.Add(line); 
      } 

     } 

     for (var i = 0; i < availibleVersions.Count; i++) 
     { 
      if (availibleVersions[i] == Version) 
      { 
       downloadlink = versionDownload[i]; 
      } 
     } 


     Client.DownloadFile(downloadlink, location + ".zip"); 

     ZipFile.ExtractToDirectory(location + ".zip", location); 
     File.Delete(location + ".zip"); 

     RunGame(Version); 
    } 

    protected void myWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 

    } 

    protected void myWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     this.Dispatcher.Invoke(() => 
     { 
      progress.Value += 10; 
     }); 
    } 

です。

EDIT: UIは今、私はあなたが右ここにブロックしているかなり確信している...

答えて

0

問題は、バックグラウンドワーカーが作業を行っている間、メインスレッドが常に動作していることであるように見えます:

while (this.myWorker.IsBusy) 
{ 
    this.Dispatcher.Invoke(() => 
    { 
     progress.Value += 10; 
    }); 
} 

は、バックグラウンドジョブが動作している間、あなたのメインスレッドは常にものをやっていることを意味し、これUIが更新されない理由です。

進捗状況の更新をバックグラウンドワーカーに移す必要があります(たとえば、ダウンロードしたavailableVersionの数を示すなど、実際には意味がある値を設定することもできます)。

希望は意味があります。

EDIT:

たちはビューで直接すべてのコードを入れて、私たちは「プログレスバー」という名前のプログレスバーと(BackgroundWorkerのを蹴る「)btnStart」という名前のボタンを持っていると仮定しますと仮定します。バックグラウンドワーカーが変更されたその進捗状況を通知するイベントが発生していることである何が起こる

private BackgroundWorker worker; 

public MainWindow() 
{ 
    InitializeComponent(); 
    this.worker = new BackgroundWorker(); 

    this.worker.DoWork += new DoWorkEventHandler(myWorker_DoWork); 
    this.worker.RunWorkerCompleted += new 
    RunWorkerCompletedEventHandler(myWorker_RunWorkerCompleted); 
    this.worker.ProgressChanged += new 
    ProgressChangedEventHandler(myWorker_ProgressChanged); 
    this.worker.WorkerReportsProgress = true; 
    this.worker.WorkerSupportsCancellation = true; 
} 

private void myWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    this.progressBar.Value = e.ProgressPercentage; 
} 

private void myWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    // Whatever you need to do when finished here (alert, update a label, etc.) 
} 

private void myWorker_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Just loop and report new progress. Sleep a little in between each 
    // progress update so that it isn't over before we have a chance to see it. 
    for(int i=0;i<100;i++) 
    { 
     Thread.Sleep(200); 
     this.worker.ReportProgress(i); 
    } 
} 

private void btnStart_Click(object sender, RoutedEventArgs e) 
{ 
    this.worker.RunWorkerAsync(); 
} 

はここで分離コードです。 メインスレッドはそのイベントのハンドルを持ち、進行状況バーを更新します。 バックグラウンドワーカーであるため、Dispatcher.Invokeを使用する必要はありません。これはすでに処理されています。

この例ではあなたのことがわかります。

+0

ありがとう!それはUIを修正しますが、プログレスバーはまだ更新されません... – WhoKnows

+0

あなたは大歓迎です。問題のコードは更新されたコードですか?または進捗状況の更新をバックグラウンドワーカーに移しましたか? また、私は他の答えにしたコメントを見たことがありますか? – kkirk

+0

私はコードを今すぐ更新しました – WhoKnows

0

を更新したが、プログレスバーはまだdoesntの仕事されています

while (this.myWorker.IsBusy) 
{ 
    this.Dispatcher.Invoke(() => 
    { 
     progress.Value += 10; 
    }); 
} 

をあなたがする必要がありますmyWorker_DoWorkメソッド内のBackgroundWorkerインスタンスにReportProgressを呼び出してください。

また、.NET 4.5以降を使用している場合は、BackgroundWorkerを完全にダンプし、async/awaitパターンを使用してこのコードを書き換えることができます。

+0

ありがとう、UIのフリーズを解除しますが、プログレスバーは変わりません – WhoKnows

+0

値にあまりにも頻繁に追加している可能性があります。元のコードでは、進捗値100にすぐに到達します。これは、それが決して変更できないことを意味します。 また、頻繁に呼び出さないようにしてください。これは、強制的にUIスレッドをブロックしていることを意味します。 – kkirk

+0

@WhoKnows On Stack Overflowでは、元の質問に答えると、別の問題があれば回答を受け入れ、新しい質問をする必要があります。 –

関連する問題