2011-11-17 95 views
0

我刚刚进入WPF,我正在尝试与后台工作者的运气,所以我想我会打开任何文件使用FileOpenDialog,通过文件内的所有字节循环,并报告总数通过worker.ReportProgress以百分比的进度...唉,这只能用于〜20倍,然后它真的卡住,并突然停止在100%。Backgroundworker不能渲染窗口

这里是我的代码:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using Microsoft.Win32; 
using System.IO; 
using System.Threading; 
using System.ComponentModel; 

namespace BitStream 
{ 
public partial class MainWindow : Window 
{ 
    private int bytes = 0; 
    private long length = 0; 

    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void selectFile_Click(object sender, RoutedEventArgs e) 
    { 
     BackgroundWorker bw = new BackgroundWorker(); 
     OpenFileDialog ofd = new OpenFileDialog(); 
     if ((bool)ofd.ShowDialog()) 
     { 
      FileInfo fi = new FileInfo(ofd.FileName); 
      this.length = fi.Length; 
      bw.DoWork += bw_DoWork; 
      bw.RunWorkerCompleted += bw_RunWorkerCompleted; 
      bw.ProgressChanged += bw_ProgressChanged; 
      bw.WorkerReportsProgress = true; 
      Stream str = ofd.OpenFile(); 

      bw.RunWorkerAsync(str); 
     } 
    } 

    private void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     Stream str = (Stream)e.Argument; 
     int singleByte = 0; 
     this.Dispatcher.Invoke(
       new Action(() => 
       { 
        int currentProgress = 0; 
        while ((singleByte = str.ReadByte()) != -1) 
        { 

         label1.Content = singleByte; 
         bytes++; 

         currentProgress = Convert.ToInt32(((double)bytes)/length * 100); 
         if (currentProgress > progress) 
         { 
          progress = currentProgress; 
          ((BackgroundWorker)sender).ReportProgress(progress); 
          Thread.Sleep(100); 
         } 
        } 
       } 

      ), System.Windows.Threading.DispatcherPriority.Render); 
    } 

    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     label2.Content = e.ProgressPercentage + "% completed"; 
    } 

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
    } 
} 

}

标签1和2是有用于显示当前字节和%目前的进展。

随意也批评我的代码的其他方面,我今天刚刚开始使用WPF。

编辑的DoWork法:

private void bw_DoWork(object sender, DoWorkEventArgs e) 
    { 
     Stream str = (Stream)e.Argument; 
     int singleByte = 0; 

     int currentProgress = 0; 
     while ((singleByte = str.ReadByte()) != -1) 
     { 
      this.Dispatcher.Invoke(
       new Action(() => 
       { 
        label1.Content = singleByte; 
       }), System.Windows.Threading.DispatcherPriority.Render); 
      bytes++; 

      currentProgress = Convert.ToInt32(((double)bytes)/length * 100); 
      if (currentProgress > progress) 
      { 
       progress = currentProgress; 
       this.Dispatcher.Invoke(
       new Action(() => 
       { 
        ((BackgroundWorker)sender).ReportProgress(progress); 


       }), System.Windows.Threading.DispatcherPriority.Render); 
       Thread.Sleep(500);   
      } 
     } 
    } 

感谢,

丹尼斯

+1

我误读了你的代码,还是你将UI线程休眠了100ms,读取的每个文件字节? – AndrewS

+0

您的阅读正确,我只是试图看看这是否与它没有任何关系,因为我用ReportProgress-Calls发送了垃圾邮件。 –

+0

是的,但现在你正在UI线程上做所有事情 - 使用BackgroundWorker没有意义。 – AndrewS

回答

1

因此,假如你真的想使一个跨线程调用每个字节(我不推荐)该代码看起来像这样:

private void bw_DoWork(object sender, DoWorkEventArgs e) 
{ 
    Stream str = (Stream)e.Argument; 
    int singleByte = 0; 
    int currentProgress = 0; 
    while ((singleByte = str.ReadByte()) != -1) 
    { 

     bytes++; 
     this.Dispatcher.Invoke( 
      new Action(() => 
      { 
        label1.Content = singleByte; 
      } 

     ), System.Windows.Threading.DispatcherPriority.Render); 

     currentProgress = Convert.ToInt32(((double)bytes)/length * 100); 
     if (currentProgress > progress) 
     { 
      progress = currentProgress; 
      ((BackgroundWorker)sender).ReportProgress(progress); 
      Thread.Sleep(100); 
     } 
    } 
} 

这个想法是,你只能在创建它的线程上操作DispatcherObject。

+0

我假设sender.ReportProgress也应该在Invoke-Method中,因为它调用了一个使用DispatcherObject的函数,对吧? 编辑:刚才看到你的评论...为什么这不需要被调用? –

+0

没有该方法引发的事件在ui线程上引发。 – AndrewS

1

首先想到的是,你并没有从openfiledialog处置返回,所以你运行它的次数越多,抛弃的资源就越多...... 我会在worker上抛出文件名,然后让它管理资源,但

using(Stream s = ofd.OpenFileDalog()) 
{ 
    get length and such 
} 
// run up woker pass filename. 

在您的调用代码将解决该问题,因为我假设你正在使用长度来整理你的进度条。