在另一个线程内操作UI元素

Unc*_*ave 4 c# user-interface multithreading invoke winforms

我试图在WinForms C#应用程序中创建一个单独的线程,启动一个控制ProgressBar(marquee)的后台工作程序.问题在于,当我尝试将条形图设置为可见时,它什么都不做,我尝试过多种形式的Invoke,但它们似乎没有帮助.

progressBarCycle从单独的线程调用以下方法.

    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;
    }
Run Code Online (Sandbox Code Playgroud)

我错过了一些明显的东西吗?评论部分是我尝试过的其他内容.

Mar*_*ell 6

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

这是一个完整的例子:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)