随机跨线程操作例外的WinForms多线程的UI操作操作、线程、多线程、WinForms

2023-09-04 22:32:21 作者:宠爱一个的一个人

由于某些原因,这是安全的前瞻性方法提出了一个经典的例外。

  

跨线程操作无效:   控制statusLabel从访问   线程比线程这是其他   上创建。

这code显然不应该通过调用调用一个匿名方法调用时需要。 但例外的,而每发生一次。

有没有人遇到过类似问题?

 私人无效SetProgressBarValue(INT progressPercentage)
    {
        行动的setValue =()=>
        {
            VAR值= progressPercentage;
            如果(progressPercentage℃,)
                值= 0;
            否则如果(progressPercentage→100)
                值= 100;
            statusProgressBar.Value =价值;
            statusLabel.Text =的String.Format({0}%,值);
        };
        如果(InvokeRequired)
            调用(的setValue);
        其他
            的setValue();
    }
 

[UPDATE2] 实施后,John桑德斯的建议,还是得到了同样的错误

 在System.Windows.Forms.Control.get_Handle()
在System.Windows.Forms.Control.SetBoundsCore(的Int32 X,的Int32 Y,的Int32宽度,高度的Int32,BoundsSpecified指定)
在System.Windows.Forms.ToolStrip.SetBoundsCore(的Int32 X,的Int32 Y,的Int32宽度,高度的Int32,BoundsSpecified指定)
在System.Windows.Forms.ToolStrip.System.Windows.Forms.Layout.IArrangedElement.SetBounds(矩形范围,BoundsSpecified指定)
在System.Windows.Forms.Layout.DefaultLayout.xLayoutDockedControl(IArrangedElement元素,矩形newElementBounds,布尔measureOnly,楼盘​​大小preferredSize,裁判矩形remainingBounds)
在System.Windows.Forms.Layout.DefaultLayout.LayoutDockedControls(IArrangedElement容器,布尔measureOnly)
在System.Windows.Forms.Layout.DefaultLayout.xLayout(IArrangedElement容器,布尔measureOnly,楼盘​​大小preferredSize)
在System.Windows.Forms.Layout.DefaultLayout.LayoutCore(IArrangedElement容器,LayoutEventArgs参数)
在System.Windows.Forms.Layout.LayoutEngine.Layout(对象容器,LayoutEventArgs layoutEventArgs)
在System.Windows.Forms.Control.OnLayout(LayoutEventArgs勒)
在System.Windows.Forms.ScrollableControl.OnLayout(LayoutEventArgs勒)
在System.Windows.Forms.Form.OnLayout(LayoutEventArgs勒)
在System.Windows.Forms.Control.PerformLayout(LayoutEventArgs参数)
在System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement,串affectedProperty)
在System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout,IArrangedElement elementCausingLayout,字符串属性)
在System.Windows.Forms.Control.PerformLayout(LayoutEventArgs参数)
在System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement,串affectedProperty)
在System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout,IArrangedElement elementCausingLayout,字符串属性)
在System.Windows.Forms.ToolStripItem.InvalidateItemLayout(字符串affectedProperty,布尔invalidatePainting)
在System.Windows.Forms.ToolStripItem.OnTextChanged(EventArgs的五)
在System.Windows.Forms.ToolStripItem.set_Text(字符串值)
在App.Image.Replace.ReplacementImageProcessForm.<>c__DisplayClassa.<>c__DisplayClassc.<SetProgressBarValue>b__9()在ReplacementImageProcessForm.cs:行147
在App.Image.Replace.ReplacementImageProcessForm.InvokeIfNecessary(调节控制,操作的setValue)在ReplacementImageProcessForm.cs:行156
在App.Image.Replace.ReplacementImageProcessForm.<>c__DisplayClassa.<SetProgressBarValue>b__7()在ReplacementImageProcessForm.cs:行145
在App.Image.Replace.ReplacementImageProcessForm.InvokeIfNecessary(调节控制,操作的setValue)在ReplacementImageProcessForm.cs:行156
在App.Image.Replace.ReplacementImageProcessForm.SetProgressBarValue(的Int32 progressPercentage)在ReplacementImageProcessForm.cs:行132
在App.Image.Replace.ReplacementImageProcessForm.replacer_BeginReplace(对象发件人,EventArgs e)在ReplacementImageProcessForm.cs:行74
在App.Image.Replace.DocumentReplacer.OnBeginReplace()在IDocumentReplacer.cs:行87
在App.Image.Replace.DocumentReplacer.Replace(的Int32 documentId,字符串replacementDocumentPath)在IDocumentReplacer.cs:行123
 
开始使用 eDEX UI 吧,一款受 电子世界争霸战 影响的终端程序 Linux 中国 技术无边 CSDN博客 linux 维基 电影 ui

[更新] 这里是堆栈跟踪的问题的完整性。

 在System.Windows.Forms.Control.get_Handle()
在System.Windows.Forms.Control.SetBoundsCore(的Int32 X,的Int32 Y,的Int32宽度,高度的Int32,BoundsSpecified指定)
在System.Windows.Forms.ToolStrip.SetBoundsCore(的Int32 X,的Int32 Y,的Int32宽度,高度的Int32,BoundsSpecified指定)
在System.Windows.Forms.ToolStrip.System.Windows.Forms.Layout.IArrangedElement.SetBounds(矩形范围,BoundsSpecified指定)
在System.Windows.Forms.Layout.DefaultLayout.xLayoutDockedControl(IArrangedElement元素,矩形newElementBounds,布尔measureOnly,楼盘​​大小preferredSize,裁判矩形remainingBounds)
在System.Windows.Forms.Layout.DefaultLayout.LayoutDockedControls(IArrangedElement容器,布尔measureOnly)
在System.Windows.Forms.Layout.DefaultLayout.xLayout(IArrangedElement容器,布尔measureOnly,楼盘​​大小preferredSize)
在System.Windows.Forms.Layout.DefaultLayout.LayoutCore(IArrangedElement容器,LayoutEventArgs参数)
在System.Windows.Forms.Layout.LayoutEngine.Layout(对象容器,LayoutEventArgs layoutEventArgs)
在System.Windows.Forms.Control.OnLayout(LayoutEventArgs勒)
在System.Windows.Forms.ScrollableControl.OnLayout(LayoutEventArgs勒)
在System.Windows.Forms.Form.OnLayout(LayoutEventArgs勒)
在System.Windows.Forms.Control.PerformLayout(LayoutEventArgs参数)
在System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement,串affectedProperty)
在System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout,IArrangedElement elementCausingLayout,字符串属性)
在System.Windows.Forms.Control.PerformLayout(LayoutEventArgs参数)
在System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement,串affectedProperty)
在System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout,IArrangedElement elementCausingLayout,字符串属性)
在System.Windows.Forms.ToolStripItem.InvalidateItemLayout(字符串affectedProperty,布尔invalidatePainting)
在System.Windows.Forms.ToolStripItem.OnTextChanged(EventArgs的五)
在System.Windows.Forms.ToolStripItem.set_Text(字符串值)
在App.Image.Replace.ReplacementImageProcessForm.<>c__DisplayClass8.<SetProgressBarValue>b__7()在ReplacementImageProcessForm.cs:行114
在App.Image.Replace.ReplacementImageProcessForm.SetProgressBarValue(的Int32 progressPercentage)在ReplacementImageProcessForm.cs:行119
在App.Image.Replace.ReplacementImageProcessForm.replacer_BeginReplace(对象发件人,EventArgs e)在ReplacementImageProcessForm.cs:行76
在App.Image.Replace.DocumentReplacer.OnBeginReplace()在IDocumentReplacer.cs:行72
在App.Image.Replace.DocumentReplacer.Replace(的Int32 documentId,字符串replacementDocumentPath)在IDocumentReplacer.cs:行108
 

解决方案

这可能是也可能不是直接关系到你的情况,但可以提供一个线索。一个重要的漏抽象要记住的Windows窗体是一个窗口处理不创建,直到真正需要它。该处理属性只创建真正的Windows HWND 上的第一个 GET 打电话,当控制派生对象(如Windows窗体)是实例化这不会发生。 (该控制派生的对象,毕竟,仅仅是一个.NET类。)换句话说,那就是被延迟初始化属性。

我已经烧毁此之前:在我的情况的问题是,我正确地实例化一个UI线程的一种形式,但我不是显示()荷兰国际集团,直到数据都来自一个Web服务调用已被运行在一个工作线程回来。该方案是,没有人的要求的表单的处理,永远,直到它被访问作为一部分 InvokeRequired ,当工作线程已完成其工作发生了检查。所以,我的后台工作线程问的形式:我需要 InvokeRequired ?该 InvokeRequired 实施形式接着说:好,让我看看我的处理这样我可以看到什么线程我内部 HWND 被创造了,然后我会看到,如果你在同一个线程。所以,那么处理实施说:好,我还不存在,所以让我创建一​​个 HWND 为自己现在。 (你看这是怎么回事。请记住,我们仍然在后台线程,傻傻地访问 InvokeRequired 属性。)

这导致了处理(及其底层 HWND )正对的工人线程,我没有自己,并没有一个消息泵,以处理Windows消息。其结果是:我的应用程序锁定,当其他电话都是以previously隐藏的窗口中进行,因为这些电话都是在主UI线程,其合理的假设上进行的所有其他控制派生的对象也已在此线程创建的。在其他情况下,这可能会导致奇怪的跨线程异常,因为 InvokeRequired 将返回false意外,因为处理创建上的螺纹是从该形式实例化的线程不同

但只是偶尔。我有这样一种功能,用户可能会导致窗体显示()本身通过一个菜单,然后它会禁用本身,而它填充自己在后台的数据(呈现活动指示器的动画)。如果他们这样做第一,那么一切会好起来的:在处理在UI线程上创建(在菜单项的事件处理程序)等 InvokeRequired 表现如预期,当工作线程完成了从Web服务中检索数据。但是,如果定期运行(这是一个事件的调度,类似于Outlook中的事件提醒对话框)我的后台线程访问的Web服务,并试图弹出的形式,并且用户还没有显示()ñ它,那么工作线程的感人 InvokeRequired 将导致上述胃灼热诱导行为。

祝你heisenbug!

For some reason, this safe-looking method raises a classic exception.

Cross-thread operation not valid: Control 'statusLabel' accessed from a thread other than the thread it was created on.

This code obviously should call an anonymous method through Invoke when invoke is required. But the exception occurs every once in a while.

Has anyone had a similar problem?

    private void SetProgressBarValue(int progressPercentage)
    {
        Action setValue = () => 
        {
            var value = progressPercentage;
            if (progressPercentage < 0)
                value = 0;
            else if (progressPercentage > 100)
                value = 100;
            statusProgressBar.Value = value;
            statusLabel.Text = string.Format("{0}%", value);
        };
        if (InvokeRequired)
            Invoke(setValue);
        else
            setValue();
    }

[UPDATE2] After implementing John Saunders's suggestion, still got the same error

at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
at System.Windows.Forms.ToolStrip.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
at System.Windows.Forms.ToolStrip.System.Windows.Forms.Layout.IArrangedElement.SetBounds(Rectangle bounds, BoundsSpecified specified)
at System.Windows.Forms.Layout.DefaultLayout.xLayoutDockedControl(IArrangedElement element, Rectangle newElementBounds, Boolean measureOnly, ref Size preferredSize, ref Rectangle remainingBounds)
at System.Windows.Forms.Layout.DefaultLayout.LayoutDockedControls(IArrangedElement container, Boolean measureOnly)
at System.Windows.Forms.Layout.DefaultLayout.xLayout(IArrangedElement container, Boolean measureOnly, ref Size preferredSize)
at System.Windows.Forms.Layout.DefaultLayout.LayoutCore(IArrangedElement container, LayoutEventArgs args)
at System.Windows.Forms.Layout.LayoutEngine.Layout(Object container, LayoutEventArgs layoutEventArgs)
at System.Windows.Forms.Control.OnLayout(LayoutEventArgs levent)
at System.Windows.Forms.ScrollableControl.OnLayout(LayoutEventArgs levent)
at System.Windows.Forms.Form.OnLayout(LayoutEventArgs levent)
at System.Windows.Forms.Control.PerformLayout(LayoutEventArgs args)
at System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement, String affectedProperty)
at System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout, IArrangedElement elementCausingLayout, String property)
at System.Windows.Forms.Control.PerformLayout(LayoutEventArgs args)
at System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement, String affectedProperty)
at System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout, IArrangedElement elementCausingLayout, String property)
at System.Windows.Forms.ToolStripItem.InvalidateItemLayout(String affectedProperty, Boolean invalidatePainting)
at System.Windows.Forms.ToolStripItem.OnTextChanged(EventArgs e)
at System.Windows.Forms.ToolStripItem.set_Text(String value)
at App.Image.Replace.ReplacementImageProcessForm.<>c__DisplayClassa.<>c__DisplayClassc.<SetProgressBarValue>b__9() in ReplacementImageProcessForm.cs: line 147
at App.Image.Replace.ReplacementImageProcessForm.InvokeIfNecessary(Control control, Action setValue) in ReplacementImageProcessForm.cs: line 156
at App.Image.Replace.ReplacementImageProcessForm.<>c__DisplayClassa.<SetProgressBarValue>b__7() in ReplacementImageProcessForm.cs: line 145
at App.Image.Replace.ReplacementImageProcessForm.InvokeIfNecessary(Control control, Action setValue) in ReplacementImageProcessForm.cs: line 156
at App.Image.Replace.ReplacementImageProcessForm.SetProgressBarValue(Int32 progressPercentage) in ReplacementImageProcessForm.cs: line 132
at App.Image.Replace.ReplacementImageProcessForm.replacer_BeginReplace(Object sender, EventArgs e) in ReplacementImageProcessForm.cs: line 74
at App.Image.Replace.DocumentReplacer.OnBeginReplace() in IDocumentReplacer.cs: line 87
at App.Image.Replace.DocumentReplacer.Replace(Int32 documentId, String replacementDocumentPath) in IDocumentReplacer.cs: line 123

[UPDATE] Here is the stack-trace for the completeness of the question.

at System.Windows.Forms.Control.get_Handle()
at System.Windows.Forms.Control.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
at System.Windows.Forms.ToolStrip.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
at System.Windows.Forms.ToolStrip.System.Windows.Forms.Layout.IArrangedElement.SetBounds(Rectangle bounds, BoundsSpecified specified)
at System.Windows.Forms.Layout.DefaultLayout.xLayoutDockedControl(IArrangedElement element, Rectangle newElementBounds, Boolean measureOnly, ref Size preferredSize, ref Rectangle remainingBounds)
at System.Windows.Forms.Layout.DefaultLayout.LayoutDockedControls(IArrangedElement container, Boolean measureOnly)
at System.Windows.Forms.Layout.DefaultLayout.xLayout(IArrangedElement container, Boolean measureOnly, ref Size preferredSize)
at System.Windows.Forms.Layout.DefaultLayout.LayoutCore(IArrangedElement container, LayoutEventArgs args)
at System.Windows.Forms.Layout.LayoutEngine.Layout(Object container, LayoutEventArgs layoutEventArgs)
at System.Windows.Forms.Control.OnLayout(LayoutEventArgs levent)
at System.Windows.Forms.ScrollableControl.OnLayout(LayoutEventArgs levent)
at System.Windows.Forms.Form.OnLayout(LayoutEventArgs levent)
at System.Windows.Forms.Control.PerformLayout(LayoutEventArgs args)
at System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement, String affectedProperty)
at System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout, IArrangedElement elementCausingLayout, String property)
at System.Windows.Forms.Control.PerformLayout(LayoutEventArgs args)
at System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.PerformLayout(IArrangedElement affectedElement, String affectedProperty)
at System.Windows.Forms.Layout.LayoutTransaction.DoLayout(IArrangedElement elementToLayout, IArrangedElement elementCausingLayout, String property)
at System.Windows.Forms.ToolStripItem.InvalidateItemLayout(String affectedProperty, Boolean invalidatePainting)
at System.Windows.Forms.ToolStripItem.OnTextChanged(EventArgs e)
at System.Windows.Forms.ToolStripItem.set_Text(String value)
at App.Image.Replace.ReplacementImageProcessForm.<>c__DisplayClass8.<SetProgressBarValue>b__7() in ReplacementImageProcessForm.cs: line 114
at App.Image.Replace.ReplacementImageProcessForm.SetProgressBarValue(Int32 progressPercentage) in ReplacementImageProcessForm.cs: line 119
at App.Image.Replace.ReplacementImageProcessForm.replacer_BeginReplace(Object sender, EventArgs e) in ReplacementImageProcessForm.cs: line 76
at App.Image.Replace.DocumentReplacer.OnBeginReplace() in IDocumentReplacer.cs: line 72
at App.Image.Replace.DocumentReplacer.Replace(Int32 documentId, String replacementDocumentPath) in IDocumentReplacer.cs: line 108

解决方案

This may or may not be directly relevant to your situation, but could provide a clue. One important leaky abstraction to remember about Windows Forms is that a window Handle is not created until it is actually required. The Handle property only creates the real Windows hwnd on the first get call, which doesn't occur when a Control-derived object (like a Windows Form) is instanced. (The Control-derived object, after all, is just a .NET class.) In other words, it's a property that is lazily initialized.

I've been burned by this before: The problem in my case is that I had correctly instanced a form on a UI thread, but I was not Show()ing it until the data had come back from a web service invocation that had been operating on a worker thread. The scenario was that no one had asked for the form's Handle, ever, until it was accessed as part of the InvokeRequired check that occurred when the worker thread had completed its work. So my background worker thread asked the form: do I need InvokeRequired? The InvokeRequired implementation of the form then said: well, let me look at my Handle so I can see what thread my internal hwnd was created on, and then I'll see if you're on that same thread. And so then the Handle implementation said: well I don't yet exist, so let me create an hwnd for myself right now. (You see where this is going. Remember, we're still on the background thread, innocently accessing the InvokeRequired property.)

This resulted in the Handle (and its underlying hwnd) being created on the worker thread, which I did not own, and which didn't have a message pump set up to handle Windows messages. The result: my app locked up when other calls were made to the previously hidden window, as these calls were made on the main UI thread, which reasonably assumed that all other Control-derived objects had also been created on this thread. In other cases, this could cause strange cross-thread exceptions because InvokeRequired would return false unexpectedly, since the Handle was created on a thread that is different from the thread that the form was instanced on.

But only sometimes. I had functionality whereby the user could cause the form to Show() itself via a menu, and then it would disable itself while it populated itself with data in the background (showing a throbber animation). If they did this first, then everything would be okay: the Handle was created on the UI thread (in the menu item's event handler), and so InvokeRequired behaved as expected when the worker thread finished retrieving data from the Web service. But if my background thread that periodically ran (it was an events scheduler, similar to the Event Reminder dialog in Outlook) accessed the Web service and tried to pop up the form, and the user hadn't yet Show()n it, then the worker thread's touching InvokeRequired would cause the heartburn-inducing behavior described above.

Good luck with your heisenbug!