Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从非GUI线程更新GUI->;不使用BeginInvoke()_C#_Multithreading_User Interface_Begininvoke - Fatal编程技术网

C# 从非GUI线程更新GUI->;不使用BeginInvoke()

C# 从非GUI线程更新GUI->;不使用BeginInvoke(),c#,multithreading,user-interface,begininvoke,C#,Multithreading,User Interface,Begininvoke,我创建了一个简单的WindowsForms应用程序,其中有一个按钮和一个标签。 如果单击按钮,则标签应显示从1到100000的数字 但是如果我单击按钮,那么GUI将冻结,直到程序计数到100000,然后标签显示100000,GUI停止冻结 从1到100000的计数在一个新线程(不是GUI线程)中执行,然后更改labeltext我尝试使用BeginInvoke,但它不起作用 using System.Drawing; using System.Linq; using System.Text; us

我创建了一个简单的WindowsForms应用程序,其中有一个
按钮
和一个
标签
。 如果单击按钮,则标签应显示从1到100000的数字

但是如果我单击
按钮
,那么
GUI
将冻结,直到程序计数到100000,然后标签显示100000,GUI停止冻结

从1到100000的计数在一个新线程(不是GUI线程)中执行,然后更改
labeltext
我尝试使用
BeginInvoke
,但它不起作用

using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e) {

            new Thread(DoSomethingExpensive).Start();

        }

        void DoSomethingExpensive() {

            for (int i = 0; i < 100000; i++) {
                this.label1.BeginInvoke((Action)(() => {
                    label1.Text = "" + i;
                    }
                    ));
            }

        }

    }
}
使用系统图;
使用System.Linq;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1{
公共部分类Form1:Form{
公共表格1(){
初始化组件();
}
私有无效按钮1\u单击(对象发送者,事件参数e){
新线程(doSomethingeExpensive).Start();
}
void dosothingexpensive(){
对于(int i=0;i<100000;i++){
此.label1.BeginInvoke((操作)(()=>{
标签1.Text=”“+i;
}
));
}
}
}
}

BeginInvoke
是异步的。这意味着它将在UI线程中执行的操作排队,然后继续其业务。在UI线程中排队执行100000个操作实际上并不需要很长时间。事实上,它比实际执行这些操作所花费的时间要少得多。这意味着队列最终被所有这些更新文本的请求所淹没。当添加一个新请求时,例如,重新绘制表单以显示新值的请求,或响应表单上的鼠标单击事件的请求,该请求将被放置在队列的末尾,排在数千个其他请求之后


如果使用
Invoke
,而不是
BeginInvoke
,则后台工作人员将不会继续对下一个项目进行排队,直到上一个项目在UI线程中完成运行,从而防止其超过UI线程并淹没队列。这意味着任何其他UI事件,例如实际重新绘制屏幕的事件,队列中最多只有一个项目需要等待。

对于每个值,都应该执行线程上下文切换。如果这样做100000次,UI线程将冻结。这是由异步调用引起的。UI线程只是执行这个委托。在调用最后一个委托时,UI没有时间从MessagePump Uniti获取工作项。消息泵通过WindowMessages触发控件的更新


现在,最后一个delgate的值被设置为控件。

这里有一种简单的反应UI方式:

public partial class Form1 : Form
{
    IDisposable subscription;
    IObservable<long> sequence;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        if (subscription != null)
            subscription.Dispose();

        sequence = Observable
            .Interval(TimeSpan.FromMilliseconds(1))
            .Take(10000); // generate a timed sequence

        subscription = sequence // act upon the sequence
            .ObserveOn(SynchronizationContext.Current)
            .Subscribe(x => label1.Text = x.ToString());
    }
}
公共部分类表单1:表单
{
可授权订阅;
可观测序列;
公共表格1()
{
初始化组件();
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
if(订阅!=null)
subscription.Dispose();
序列=可观察
.间隔(时间跨度从毫秒(1))
.Take(10000);//生成一个定时序列
订阅=顺序//按顺序操作
.ObserveOn(SynchronizationContext.Current)
.Subscribe(x=>label1.Text=x.ToString());
}
}

取决于当前包

@Vkt0rS。在这种情况下,这不会真正改变任何事情,也不会提供任何特别有用的工具。虽然BGW总体上很好,但它并不是真正设计用来处理这个特殊问题的。@Servy怎么会这样?这似乎正是bgw设计的用途。您希望在长时间运行的过程中向UI线程发送更新。@DanielMann为什么不亲自尝试一下,看看是否可以将此代码重新写入一个利用BGW工具的有效且有效的解决方案中。您将看到它与本问题中的问题完全相同。这不是很准确,BeginInvoke()请求也放在消息队列的末尾。问题是有两个队列,Windows实现的消息队列和存储委托的调用队列。单个调用将导致UI线程使用所有调用队列条目。当前一个委托目标完成执行时,如果还有另一个委托目标准备被调用,则该委托将永不停止。@HansPassant我不明白你的最后一句话。你能重新表述一下吗?它会循环直到调用队列为空。“它永远不会变空。”汉帕桑为什么它不会变空?除非有其他不相关的操作在队列中填充大量委托,在这种情况下,这将是需要解决的问题。因为执行委托目标所需的时间比工作线程添加另一个委托目标所需的时间要长。
对于每个值,都会执行线程上下文切换。
No,实际上,事实并非如此。事实上,如果是这样的话,那么代码实际上是可以工作的。问题是没有足够快的上下文切换。您可以正确地说,UI线程除了执行这些委托之外几乎什么都不做,但它不一定在执行其他任何操作之前执行所有委托(尽管它可能会)。你也没有解释OP是如何修复代码的。