【问题标题】:Backgroundworker not Rendering Window fluentlyBackgroundworker 不能流畅地渲染窗口
【发布时间】: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


【解决方案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 的线程上操作它。

【讨论】:

  • 我假设 sender.ReportProgress 也应该在 Invoke-Method 中,因为它调用了一个使用 DispatcherObject 的函数,对吧?编辑:刚刚看到你的评论......为什么不需要调用它?
【解决方案2】:

首先想到的是你没有处理来自 openfiledialog 的返回,所以你运行它的次数越多,你丢弃的资源就越多...... 我会把文件名扔给工人,然后让它管理资源,但是

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

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

【讨论】:

    猜你喜欢
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多