后台工作器ReportProgress方法不会触发ProgressChanged事件

时间:2015-05-16 03:55:09

标签: c# wpf

我正在尝试在WPF应用程序中报告进度条的进度,但似乎我的后台工作者的reportProgress不会触发事件。

这是我的代码: -

XAML

<Window x:Class="nk_Image_Converter.DynamicControls.ProgressBarWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ProgressBarWindow" Height="100" Width="500" BorderThickness="0" WindowStyle="None" ResizeMode="NoResize" Background="#d4dce6" Loaded="Window_Loaded" >
<Window.Effect>
    <DropShadowEffect Opacity="0.4"/>
</Window.Effect>
<Border BorderBrush="CadetBlue" BorderThickness="3,0,3,3">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" Background="CadetBlue"></Grid>
        <Grid Grid.Row="1" Background="Transparent">
            <Label x:Name="Message" Content="Please Wait..." Margin="42,15"/>
            <ProgressBar x:Name="Progressbar" Width="400" Height="25" Margin="47,38,47,14" Foreground="CadetBlue" BorderBrush="CadetBlue" BorderThickness="2"></ProgressBar>
        </Grid>

    </Grid>
</Border>

C#

public partial class ProgressBarWindow : Window
{
    private double _progressCounter = 0;
    private double _progress = 0;
    private BackgroundWorker backgroundWorker = new BackgroundWorker();

    public ProgressBarWindow()
    {
        InitializeComponent();
        this.Left = Application.Current.MainWindow.Left + 250;
        this.Top = Application.Current.MainWindow.Top + 200;
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
        backgroundWorker.DoWork += backgroundWorker_DoWork;
        backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
        this.Progressbar.Value = 0;
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        backgroundWorker.RunWorkerAsync();
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        this.Dispatcher.Invoke((Action)(() =>
        {
            this._progress = 0;
            addRowstoGrid();
            _progressCounter = (100 / ((MainWindow)Application.Current.MainWindow).fetcher.getNewFiles().Count);

            for (int i = 0; i < ((MainWindow)Application.Current.MainWindow).fetcher.getNewFiles().Count; i++)
            {
                Thread.Sleep(10);
                DynamicControls.ImageButton b = new DynamicControls.ImageButton();
                ((MainWindow)Application.Current.MainWindow)._imageContainer.Height = ((((MainWindow)Application.Current.MainWindow).row + 1) * 125);
                ((MainWindow)Application.Current.MainWindow)._imageContainer.ImageGrid.Height = ((MainWindow)Application.Current.MainWindow)._imageContainer.Height;
                Grid.SetRow(b, ((MainWindow)Application.Current.MainWindow).row);
                Grid.SetColumn(b, ((MainWindow)Application.Current.MainWindow).col++);
                if ((((MainWindow)Application.Current.MainWindow).col + 1) % 5 == 0 && (((MainWindow)Application.Current.MainWindow).col + 1) >= 5)
                {
                    ((MainWindow)Application.Current.MainWindow).col = 0;
                    ++((MainWindow)Application.Current.MainWindow).row;
                }
                ((MainWindow)Application.Current.MainWindow)._imageContainer.ImageGrid.Children.Add(b);
                if (_progressCounter < 99)
                    this._progress += _progressCounter;
                if (_progress > 100)
                    _progress = 100;

                this._progress += ((_progressCounter + _progress) <= 100) ? _progressCounter : 100;


                (sender as BackgroundWorker).ReportProgress((int)this._progress, this._progress);
            }
        }));
    }

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

    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.Progressbar.Value = (double)e.UserState;
    }

    public void showDialog()
    {
        ShowDialog();
    }

我也尝试在每个事件方法上添加断点并调试它,但我没有得到任何解决方案

1 个答案:

答案 0 :(得分:2)

问题在于,当您调用Dispatcher.Invoke时,代码在调度程序线程上运行,而不是在后台线程上运行。这可能是它未能报告进展的原因。

你应该:

a)更改您的代码,以便它根本不使用后台工作程序

b)更改后台工作程序,使其不在调度程序线程上运行代码。

c)如果需要,可以更改后台工作程序,使其在调度程序线程上运行一些零碎,但不是所有内容。您可能只需要在调度程序线程上运行与UI相关的东西;像这样的东西:

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    this._progress = 0;
    addRowstoGrid();
    _progressCounter = (100 / ((MainWindow)Application.Current.MainWindow).fetcher.getNewFiles().Count);

    for (int i = 0; i < ((MainWindow)Application.Current.MainWindow).fetcher.getNewFiles().Count; i++)
    {
        Thread.Sleep(10);

        this.Dispatcher.Invoke((Action)(() =>
        {
            DynamicControls.ImageButton b = new DynamicControls.ImageButton();
            ((MainWindow)Application.Current.MainWindow)._imageContainer.Height = ((((MainWindow)Application.Current.MainWindow).row + 1) * 125);
            ((MainWindow)Application.Current.MainWindow)._imageContainer.ImageGrid.Height = ((MainWindow)Application.Current.MainWindow)._imageContainer.Height;
            Grid.SetRow(b, ((MainWindow)Application.Current.MainWindow).row);
            Grid.SetColumn(b, ((MainWindow)Application.Current.MainWindow).col++);
            if ((((MainWindow)Application.Current.MainWindow).col + 1) % 5 == 0 && (((MainWindow)Application.Current.MainWindow).col + 1) >= 5)
            {
                ((MainWindow)Application.Current.MainWindow).col = 0;
                ++((MainWindow)Application.Current.MainWindow).row;
            }
            ((MainWindow)Application.Current.MainWindow)._imageContainer.ImageGrid.Children.Add(b);
        }));
        if (_progressCounter < 99)
            this._progress += _progressCounter;
        if (_progress > 100)
            _progress = 100;

        this._progress += ((_progressCounter + _progress) <= 100) ? _progressCounter : 100;

        (sender as BackgroundWorker).ReportProgress((int)this._progress, this._progress);
    }
}

我不确定addRowstoGrid的作用,但也可能需要在调度程序线程上运行。您可以考虑从构造函数而不是后台线程调用它。 重要的部分是在后台线程上调用ReportProgress

另外,作为注释,fetcher.getNewFiles()将被多次调用 - 每次迭代循环一次。那是你想要的吗?