从另一个线程中操作UI元素 [英] Manipulating UI elements from within another thread

查看:189
本文介绍了从另一个线程中操作UI元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想有一个WinForms C#应用程序一个单独的线程启动一个后台工作,它控制进度(字幕)。问题是,当我尝试到酒吧设置为可见少了点什么,我试过调用的许多形式,但他们似乎并没有帮助。

I'm trying to have a seperate thread in a WinForms C# application start a background worker which controls a ProgressBar (marquee). The issue is that when i try to set the bar to visible it just does nothing, and i've tried many forms of Invoke but they don't seem to help.

下面的方法 progressBarCycle 是由一个单独的线程调用。

The following method progressBarCycle is called from a separate thread.

    BackgroundWorker backgroundWorker = new BackgroundWorker();

    public void progressBarCycle(int duration)
    {
        backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
        backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
        backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
        backgroundWorker.WorkerReportsProgress = true;
        backgroundWorker.WorkerSupportsCancellation = true;
        backgroundWorker.RunWorkerAsync(duration);
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        worker.ReportProgress(0);

        DateTime end = DateTime.Now.AddMilliseconds((int)e.Argument);
        while (DateTime.Now <= end)
        {
            System.Threading.Thread.Sleep(1000);
        }
    }

    private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (!this.IsHandleCreated)
            this.CreateHandle();
        statusStrip1.Invoke((MethodInvoker)delegate
        {
            progressBar1.Visible = false;
        });
        //    if (!this.IsHandleCreated)
        //    {
        //        this.CreateHandle();
        //        if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = false));
        //        else progressBar1.Visible = false;
        //    }
        //    else
        //        if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = false));
        //        else progressBar1.Visible = false;
    }

    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (!this.IsHandleCreated)
            this.CreateHandle();
        statusStrip1.Invoke((MethodInvoker)delegate
        {
            progressBar1.Visible = true;
        });
        //    if (!this.IsHandleCreated)
        //    {
        //        this.CreateHandle();
        //        if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = true));
        //        else progressBar1.Visible = true;
        //    }
        //    else
        //        if (InvokeRequired) this.Invoke((MethodInvoker)(() => progressBar1.Visible = true));
        //        else progressBar1.Visible = true;
    }



我在这里丢失了一些东西明显?注释部分是其他的事情我已经试过。

Am I missing something obvious here? The comment sections are other things I've tried.

推荐答案

ProgressChanged 是的的提出的UI线程(通过同步上下文);你的 ProgressChanged 不需要做调用 - 它可以直接操作UI(相比之下,的DoWork 绝对可以的不可以这样做)。也许真正的问题是,你没有做任何 worker.ReportProgress(...) 的内环路 - 因此它只能在发生一次。启动

ProgressChanged is already raised on the UI thread (via the sync-context); your ProgressChanged does not need to do that Invoke - it can manipulate the UI directly (by contrast, DoWork can absolutely not do that). Perhaps the real problem is that you don't do any worker.ReportProgress(...) inside the loop - so it only happens once at the start.

下面是一个完整的例子:

Here's a full example:

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        using (var worker = new BackgroundWorker {
            WorkerReportsProgress = true })
        using (var progBar = new ProgressBar {
            Visible = false, Step = 1, Maximum = 100,
            Dock = DockStyle.Bottom })
        using (var btn = new Button { Dock = DockStyle.Top, Text = "Start" })
        using (var form = new Form { Controls = { btn, progBar } })
        {
            worker.ProgressChanged += (s,a) => {
                progBar.Visible = true;
                progBar.Value = a.ProgressPercentage;
            };
            worker.RunWorkerCompleted += delegate
            {
                progBar.Visible = false;
            };
            worker.DoWork += delegate
            {
                for (int i = 0; i < 100; i++)
                {
                    worker.ReportProgress(i);
                    Thread.Sleep(100);
                }
            };
            btn.Click += delegate
            {
                worker.RunWorkerAsync();
            };
            Application.Run(form);
        }
    }
}

这篇关于从另一个线程中操作UI元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆