简体   繁体   English

Backgroundworker 不单独更新进度条 window

[英]Backgroundworker doesn't update progress bar in separate window

I got this to work in Indeterminate mode, but wanted to show actual progress.我让它在不确定模式下工作,但想显示实际进度。

When I try to update from within the BackgroundWorker, I get the error "The calling thread cannot access this object because a different thread owns it."当我尝试从 BackgroundWorker 中更新时,出现错误“调用线程无法访问此 object,因为另一个线程拥有它。” However, the examples I see seem to be doing what I'm trying to do.但是,我看到的示例似乎正在做我想做的事情。 Most of the tutorials use a progress bar in the main window, I want a separate window that appears while the action is happening.大多数教程在主 window 中使用进度条,我想要一个单独的 window 在操作发生时出现。 This is.Net 4这是.Net 4

Progress Bar Window进度条 Window

<Window x:Class="WpfTest.ProgressBarPopup"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ProgressBarPopup" Height="100" Width="300">
    <Grid Margin="20">
        <ProgressBar Minimum="0" Maximum="100" Height="20" x:Name="UpdateProgress" Value="10" IsIndeterminate="False" />
        <!-- {Binding Path=PercentDone}-->
    </Grid>
</Window>

Code behind:代码背后:

namespace WpfTest
{
    /// <summary>
    /// Interaction logic for ProgressBarPopup.xaml
    /// </summary>
    public partial class ProgressBarPopup : Window
    {
        public ProgressBarPopup()
        {
            InitializeComponent();
            UpdateProgress.Value = 60;
        }
    }
}

Main window: (I deleted some stuff about an ObservableCollection to unclutter the code.) Main window:(我删除了一些关于 ObservableCollection 的内容以整理代码。)

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 System.ComponentModel; // for background task
using System.Threading;    // for thread.sleep

namespace WpfTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {    
        ProgressBarPopup bar = new ProgressBarPopup();

        bool barExists = true;

        public MainWindow()
        {
            InitializeComponent();    
        }

        private void Progress_Click(object sender, RoutedEventArgs e)
        {
            if (!barExists)
            {
                bar = new ProgressBarPopup();
                barExists = false;
            }

            bar.Show();
#if true
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunCompleted);

            worker.RunWorkerAsync();
#else       
            // this simple method of doing work in foreground doesn't work with progress bars
            for (int i = 0; i < 50; i++)
            {
                Thread.Sleep(100);
            }
            bar.Hide();
            bar.Close();  // need to clean up
#endif
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            for (int i = 0; i < 50; i++)
            {
                bar.UpdateProgress.Value = i*2;       //  <<<=== gives Error here 
                Thread.Sleep(100);
            }
        }

        void worker_RunCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            bar.Hide();
            bar.Close();
            barExists = false;
        }
    }
}

You can't access the UI thread from the DoWork() method since the code in that method is running on a separate thread. 您无法从DoWork()方法访问UI线程,因为该方法中的代码在单独的线程上运行。 You must use the BackgroundWorker.ProgressChanged Event and BackgroundWorker.ReportProgress Method for that... 您必须为此使用BackgroundWorker.ProgressChanged事件和BackgroundWorker.ReportProgress方法。

You will have to invoke the controls like so. 您将必须像这样调用控件。 Form controls run on there own thread. 表单控件在自己的线程上运行。 Since the background worker runs separately it does not have the sufficient privileges to access that control. 由于后台工作程序是单独运行的,因此它没有足够的特权来访问该控件。 Please Look at the MethodInvoker to separate your controls from your background worker. 请查看MethodInvoker,以将您的控件与后台工作人员分开。

void worker_RunCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
           _RunCompleted();
        }


private void _RunCompleted(){
MethodInvoker action = delegate
            {
           bar.Hide();
            bar.Close();
            barExists = false;
};
}

Only the Progress Changed of the backgroundworker is thread safe so you should do any changes to the UI from the progress changed but not limited to UI only.只有后台工作程序的 Progress Changed 是线程安全的,因此您应该从进度更改对 UI 进行任何更改,但不仅限于 UI。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 System.ComponentModel; // for background task
using System.Threading;    // for thread.sleep

namespace WpfTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {    
        ProgressBarPopup bar = new ProgressBarPopup();

        bool barExists = true;

        public MainWindow()
        {
            InitializeComponent();    
        }

        private void Progress_Click(object sender, RoutedEventArgs e)
        {
            if (!barExists)
            {
                bar = new ProgressBarPopup();
                barExists = false;
            }

            bar.Show();
#if true
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunCompleted);

            worker.RunWorkerAsync();
#else       
            // this simple method of doing work in foreground doesn't work with progress bars
            for (int i = 0; i < 50; i++)
            {
                Thread.Sleep(100);
            }
            bar.Hide();
            bar.Close();  // need to clean up
#endif
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            for (int i = 0; i < 50; i++)
            {
                worker.reportprogress(i)
                Thread.Sleep(100);
            }
        }

       void worker_ProgressChanged(object sender, DoWorkEventArgs e)

{
    int i=e.progresschanged
     bar.UpdateProgress.Value = i*2;       //  <<<=== gives Error here 
}

        void worker_RunCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            bar.Hide();
            bar.Close();
            barExists = false;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM