WPF ProgressBar 控件调度仍然阻塞 UI 线程

发布于 2024-10-20 04:17:20 字数 574 浏览 0 评论 0原文

我正在使用 WPF 尝试在后台运行一个线程来更新进度栏。我不想阻止 UI 线程,因此我运行以下代码。然而,UI 仍然被阻止。看起来很简单,我做错了什么?

       Dispatcher.BeginInvoke(
        (ThreadStart) delegate(){                   
            for(double i = progressBar_ChangeProgress.Minimum;
                i < progressBar_ChangeProgress.Maximum;
                i++)
                {
                    for (int b = 0; b < 100000000; b++) { }
                    progressBar_ChangeProgress.Value = i;
                }
            EnableAllInputControls();
        }, DispatcherPriority.Background);

I am using WPF trying to run a Thread in the background that updates a progress bar. I don't wan to block the UI thread so I am running the following code. However the UI still blocked. It seems so simple, what am I doing wrong?

       Dispatcher.BeginInvoke(
        (ThreadStart) delegate(){                   
            for(double i = progressBar_ChangeProgress.Minimum;
                i < progressBar_ChangeProgress.Maximum;
                i++)
                {
                    for (int b = 0; b < 100000000; b++) { }
                    progressBar_ChangeProgress.Value = i;
                }
            EnableAllInputControls();
        }, DispatcherPriority.Background);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

相守太难 2024-10-27 04:17:20

在这种情况下为什么不利用BackgroundWorker...

        void Go()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerAsync();
        }

        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar_ChangeProgress.Value = e.ProgressPercentage;
        }

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

更新:

如果您想使用Dispatcher;将优先级设置为 Normal 并在后台线程上执行处理,然后调用 UI 线程上的方法来提供更新。

        void Go()
        {
            ThreadStart start = delegate()
            {
                //this is taking place on the background thread
                for (int i = 0; i < 100; i++)
                {
                    //this is slowing things down; no real relevance
                    Thread.Sleep(100);

                    //this will marshal us back to the UI thread
                    Dispatcher.Invoke(DispatcherPriority.Normal,
                                         new Action<int>(Update), i
                                         );
                }

            };

            new Thread(start).Start();
        }

        void Update(int value)
        {
            //this is taking place on the UI thread
            _progressBar.Value = value;
        }

Why not leverage the BackgroundWorker in this scenario...

        void Go()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerAsync();
        }

        void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar_ChangeProgress.Value = e.ProgressPercentage;
        }

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

UPDATE:

If you are wanting to use the Dispatcher; set the priority to Normal and perform the processing on the background thread then calling a method on the UI thread to provide the update.

        void Go()
        {
            ThreadStart start = delegate()
            {
                //this is taking place on the background thread
                for (int i = 0; i < 100; i++)
                {
                    //this is slowing things down; no real relevance
                    Thread.Sleep(100);

                    //this will marshal us back to the UI thread
                    Dispatcher.Invoke(DispatcherPriority.Normal,
                                         new Action<int>(Update), i
                                         );
                }

            };

            new Thread(start).Start();
        }

        void Update(int value)
        {
            //this is taking place on the UI thread
            _progressBar.Value = value;
        }
猫性小仙女 2024-10-27 04:17:20

Dispatcher 只是一种稍后在 UI 线程上运行一些代码的机制。您传入的优先级控制何时它将被执行,而不是任何类型的线程优先级。在这种情况下,委托的内容正在 UI 线程上运行。使用 Aaron 提到的 BackgroundWorker 肯定会有所帮助。

我还可能指出,通常进度条会显示任务距离完成的程度。如果您不知道某件事需要多长时间或无法衡量进度,则可以使用不确定进度条。仅当您有一些有意义的信息时才更新该值。 (尽管您可能只是出于演示目的提供了此信息)

The Dispatcher is just a mechanism to run a bit of code on the UI thread at a later time. The priority you're passing in controls when it will get executed, not any type of thread priority. The contents of your delegate in this case are getting run on the UI thread. Using a BackgroundWorker as mentioned by Aaron would certainly help here.

Also I might point out that usually a progress bar shows how close a task is to completing. If you don't know how long something is going to take or have no way of measuring progress, you can use an Indeterminate progress bar. Only update the value if you have some meaningful information. (though you may have just provided this for demonstration purposes)

似狗非友 2024-10-27 04:17:20

BeginInvoke 中的所有内容都在 UI 线程上运行,因此它将阻塞。

您需要做的是在线程中运行任何时间密集型代码,然后只需更新 Invoke 内的 UI。

你想要更多这样的东西:

for (double i = progressBar_ChangeProgress.Minimum;
    i < progressBar_ChangeProgress.Maximum;
    i++)
{
  for (int b = 0; b < 100000000; b++) { }
  Dispatcher.Invoke((ThreadStart) delegate(){                   
    progressBar_ChangeProgress.Value = i;
  });
}

Everything inside BeginInvoke is being run on the UI thread and so it will block.

What you need to do is run any time intensive code in your thread and then just update the UI inside the Invoke.

You want something more like this:

for (double i = progressBar_ChangeProgress.Minimum;
    i < progressBar_ChangeProgress.Maximum;
    i++)
{
  for (int b = 0; b < 100000000; b++) { }
  Dispatcher.Invoke((ThreadStart) delegate(){                   
    progressBar_ChangeProgress.Value = i;
  });
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文