C# 接口未更改-winforms

C# 接口未更改-winforms,c#,winforms,user-interface,C#,Winforms,User Interface,我有一个函数,当函数启动时,我想显示一些UI组件,然后开始工作,最后,我想从那里删除这些组件。问题是我在表单上看不到UI的变化 我这样做的功能是: public void Processor() { // ------------- SETTING UI COMPONENTS lblProgress.Visible = true; progressBar.Visible = true; btnStop.Visible = true; // -----

我有一个函数,当函数启动时,我想显示一些UI组件,然后开始工作,最后,我想从那里删除这些组件。问题是我在表单上看不到UI的变化

我这样做的功能是:

public void Processor()
{
    // ------------- SETTING UI COMPONENTS 

    lblProgress.Visible = true;
    progressBar.Visible = true;
    btnStop.Visible = true;

    // ------------- WORKING

    int counter = 0, percent = 0;
    foreach (string url in Urls)
    {
        .... WORKING THAT TAKES TIME

        counter += 1;
        percent = ((counter * 100) / Urls.Count());

        // ------------- MODIFYING UI COMPONENTS
        // Modification doesn't appear on the form while running

        lblProgress.Text = "Progress: " + (percent > 100 ? 100 : percent) + "%";
        progressBar.Value = percent;
    }

    // ------------- SETTING UI COMPONENTS

    lblProgress.Visible = false;
    progressBar.Visible = false;
    btnStop.Visible = false;
    lblDone.Visible = true;
}

有人能帮忙吗。如果我做错了什么,请告诉我。

作为Vimalan回答的补充:

Application.DoEvents()
强制在windows消息队列中泵送消息。这意味着任何挂起的UI更新请求都是通过
Application.DoEvents()
调用的,因此这是一种蛮力方法。我建议通过删除需要花费时间来处理并在seprate线程上运行的代码块,使您的UI具有响应性。现在,需要时间的代码也在主线程上运行(UI也在主线程上运行)。我想说,这会扼杀主线程,难以消化;)

请尝试阅读以下异步编程模式以了解更多信息:

或者您可以使用后台工作程序:

请不要使用
.DoEvents()
。它会导致代码中出现各种各样的重入问题,并会破坏第三方代码。实际上,它也可以破坏内置的Windows窗体代码,这取决于您正在执行的操作

我当然会建议
BackgroundWorker
作为解决此问题的库存标准方法

一、 然而,我更喜欢使用微软的反应式框架来处理这类事情。这样做很简单

以下是我应该如何解决这个问题:

public void Processor()
{
    // ------------- SETTING UI COMPONENTS 

    lblProgress.Visible = true;
    progressBar.Visible = true;
    btnStop.Visible = true;

    // ------------- WORKING

    Urls
        .ToObservable(Scheduler.Default) // Goes to background thread
        .Do(url =>
        {
            /* .... WORKING THAT TAKES TIME */
        })
        .Select((url, counter) => counter * 100 / Urls.Count())
        .DistinctUntilChanged()
        .ObserveOn(this) // back to the UI thread
        .Subscribe(
            percent => // Done each change in percent
            {
                lblProgress.Text = "Progress: " + (percent > 100 ? 100 : percent) + "%";
                progressBar.Value = percent;
            },
            () => // Done when finished processing
            {
                lblProgress.Visible = false;
                progressBar.Visible = false;
                btnStop.Visible = false;
                lblDone.Visible = true; 
            });
}

您可以使用“Rx WinForms”来获得所有这些好处。

@user2831683,我想您现在知道使用Application.DoEvents是不可取的。以下是您可以使用的另一种选择:

async public void Processor() //see the "async" keyword
{
   //SETTING UI COMPONENTS 

   foreach (string url in Urls)
   {
        await Task.Run(() =>
        {
             //.... WORKING THAT TAKES TIME

        });

        //MODIFYING UI COMPONENTS
   }
}
虽然
DoEvents
使您的代码看起来正常工作,但大部分时间您的UI仍然被您的工作阻塞。这种方法将允许您的UI进行更平滑的更新(例如,在移动窗口时等)


PS:原始代码中唯一的更改是零件
/。。。。需要时间的工作
,由任务取代

我总共有1066个URL,每个URL需要大约6秒的处理器。在写入控件后,尝试使用Application.DoEvents()。@user2831683虽然您似乎喜欢下面的答案,但它并不像您想象的那么好。阅读此解决方案:使用任务,异步/等待。请不要使用
.DoEvents()
。请参阅我对Vimalan答案的评论。是的,这是另一个很好的方法-但是我认为您需要显示进度条是如何更新的,因为任务中的代码需要封送回UI线程。@Enigmativity与前面讨论的一样。不需要额外的代码。如果OP不访问其工作块中的任何UI组件,我看不出有任何问题。任务的工作不会操纵UI组件。据我所知,任务的工作可能会使处理器忙,UI组件会因此进入块队列而不响应。@user2831683所有UI更新都由一个线程处理。如果您让它保持忙碌,您的界面将没有响应。这就是全部想法。@EZI-OP正在更新循环中的进度条。这需要在UI线程上完成。