【发布时间】:2011-11-18 05:52:01
【问题描述】:
我刚进入 WPF,目前正在与后台工作人员一起试试运气,所以我想我只需使用 FileOpenDialog 打开任何文件,循环遍历文件中的所有字节并通过 @ 报告总进度987654322@ 百分比...唉,这仅适用于大约 20 次,然后它真的卡住并突然停在 100%。
这是我的代码:
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);
}
}
}
谢谢,
丹尼斯
【问题讨论】:
-
我是否误读了您的代码,或者您是否在读取文件的每个字节时让 UI 线程休眠 100 毫秒?
-
你没看错,我只是想看看这是否与它更新不流畅有关,因为我用 ReportProgress-Calls 向线程发送垃圾邮件。
-
是的,但现在你在 UI 线程上做所有事情 - 使用 BackgroundWorker 毫无意义。
-
所以为了清楚起见,DoWork 方法是在后台线程上调用的。当您在 Dispatcher 上调用 Invoke/BeginInvoke 时,这意味着您正在调用的委托将在 UI 线程上执行。
-
ReportProgress 不需要在 UI 线程上调用。
标签: c# wpf multithreading backgroundworker