在WPF中使用BackgroundWorker和ProgressBar

3

你好,我有一个应用程序,其中一个任务是将Excel转换并将所有记录传递到数据库。

由于我将获得并插入超过7000行数据,所以这需要一些时间。

因此,由于这项任务需要花费一些时间,超过3分钟,我想使用进度条来报告此任务的进度。

如果我在创建的类中执行此任务,我该如何使用backgroundWorker将进度报告给我的进度条?

我的目标是准确地显示进度百分比,并了解如何使用所有这些内容来报告进度。我以前从未使用过backgroundWorkers。

我认为,这只是一个提示,也许好的或不好的,我首先获取Excel中的行数,将该数字作为ProgressBar中的某个Maxvalue,然后对于每一行或在一定时间间隔内报告进度。

这可行吗? 我该怎么做?

2个回答

4

我喜欢使用绑定来控制进度条(以及尽可能多的其他内容),因为这样你就不需要担心调度到UI线程

基本上,你需要创建一个实现INotifyPropertyChanged接口的类,其中包含一个进度属性,你可以将进度条绑定到该属性。例如:

public class Task : INotifyPropertyChanged
{
    private int _progress = 0;
    public int Progress
    {
        get { return _progress; }
        private set
        {
            if (_progress != value)
            {
                _progress = value;
                OnPropertyChanged("Progress");
            }
        }
    }

    public Task(ref ProgressChangedEventHandler progressChangedEvent)
    {
        progressChangedEvent += (s, e) => Progress = e.ProgressPercentage;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

这个类在构造函数中使用一个事件,如果触发,将更新任务的进度。但是您可以以任何您喜欢的方式处理进度更改,例如通过方法或使Progress属性 public,以便随意更改它。


使用示例:

<ProgressBar Minimum="0" Maximum="100" Height="20"
             Value="{Binding UpdateTask.Progress, Mode=OneWay}"/>

// The event that should be raised when a progress occurs.
private event ProgressChangedEventHandler UpdateProgressChanged;

// The task the ProgressBar binds to.
private readonly Task _updateTask;
public Task UpdateTask
{
    get { return _updateTask; }
}

public MainWindow()
{
    // Instatiate task, hooking it up to the update event.
    _updateTask = new Task(ref UpdateProgressChanged);
}

private void OnUpdateProgressChanged(int progressPercentage)
{
    if (UpdateProgressChanged != null)
    {
        UpdateProgressChanged(this, new ProgressChangedEventArgs(progressPercentage, null));
    }
}

// Simple progress simulation
private void Button1_Click(object sender, RoutedEventArgs e)
{
    int progress = 0;
    DispatcherTimer timer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(0.5) };
    timer.Tick += (sSub,eSub) =>
    {
        progress++;
        // Raise progress changed event which in turn will change
        // the progress of the task which in turn will cause
        // the binding to update which in turn causes the value
        // of the ProgressBar to change.
        OnUpdateProgressChanged(progress);
        if (progress == 100)
        {
            timer.Stop();
        }
    };
    timer.Start();
}

添加了一个示例,并且修复了任务类中的错误,构造函数需要通过引用(ref关键字)获取事件。 - H.B.
好的,我创建了一个新的WPF应用程序项目,并选择了你的示例,在测试过后发现进度条的值是否被更新。在OnUpdatedProgressChanged方法的末尾,我使用了一个MessageBox来显示每次进度属性增加时进度条的值,但是这个值始终不变。它总是0,但是属性确实被递增了... - Miguel
你是否对Task类进行了更改,需要将事件通过引用传递? - H.B.
1
正如我之前所说,绑定是否有效,输出窗口中是否有任何错误?我的代码不完整,我使用DataContext进行绑定。如果您对绑定不是很熟悉,请阅读概述 - H.B.
当他尝试绑定时,输出窗口会报告一些警告,就好像他正在尝试绑定到属性,但由于某种原因他无法绑定。 - Miguel
显示剩余7条评论

1
这是一个带进度的后台工作线程的示例。
但是,请仔细检查以确保 BGW 在您的情况下能够正常工作。如果您通过 COM 互操作控制 Excel,则可能需要一个 STA 线程(而 BGW 是 MTA 线程,不是 STA)。
如果是这种情况,您将需要使用具有STA调度程序Task,或者您自己的手动Thread(我强烈建议使用基于Task的方法)。

1
是的,我正在使用Com Interop。所以你所说的Task方法是指在带有进度的后台工作器中提到的那个方法,对吗? - Miguel
是的,除非您使用我提供链接的StaTaskScheduler - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接