编辑显然不需要调用的控件时出现异常

时间:2013-06-08 16:48:04

标签: c# multithreading invoke

我试图从另一个线程更改控件上的Text属性。我使用这种方法来做到这一点:

        public static void InvokeIfRequired(this Control control, MethodInvoker action)
        {
            if (control.InvokeRequired)
            {
                try
                {
                    control.Invoke(action);
                }
                catch (ObjectDisposedException) { }
                catch (InvalidAsynchronousStateException) { }
            }
            else
            {
                action();
            }
        }

使用此方法时,我仍然遇到'System.InvalidOperationException'异常。当我闯入这个时,我可以看到control.InvokeRequiredfalse,但看起来它实际上是从另一个线程访问的?

在实际的错误消息中,它不会给我与我尝试调用的控件相同。相反,它给了我控件所在的表单,说明'Form1 accessed from a thread other than the thread it was created on'.

我尝试将表单传递给InvokeIfRequired方法,但Form1.InvokeRequired仍为false,并发生异常。我试图调用的控件是在设计器中创建的。

以下是我用来编辑控件的代码:

        private void StartUpdateThreads()  // called from the Form ctor
        {
            new Thread(new ThreadStart(this.TimeUpdater)).Start();
            new Thread(new ThreadStart(this.AccountBalanceUpdater)).Start();
        }

        private void TimeUpdater()
        {
            while (!this.IsDisposed)
            {
                Utilities.InvokeIfRequired(this, (MethodInvoker)(() =>
                    {
                        this.timestampLabel.Text = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss");
                    }));
                Thread.Sleep(250);
            }
        }

这是调用堆栈:

    MyApp.exe!MyApp.MyAppToolbar.TimeUpdater.AnonymousMethod__0() Line 133 + 0x41 bytes 
    MyApp.exe!MyApp.Utilities.InvokeIfRequired(System.Windows.Forms.Control control, System.Windows.Forms.MethodInvoker action) Line 34 + 0xb bytes 
    MyApp.exe!MyApp.MyAppToolbar.TimeUpdater() Line 131 + 0x49 bytes

这是堆栈跟踪:

    at System.Windows.Forms.Control.get_Handle()\r\n   
    at System.Windows.Forms.Control.get_InternalHandle()\r\n   
    at System.Windows.Forms.Control.get_CreateParams()\r\n   
    at System.Windows.Forms.Label.get_CreateParams()\r\n   
    at System.Windows.Forms.Control.SizeFromClientSize(Int32 width, Int32 height)\r\n   
    at System.Windows.Forms.Control.SizeFromClientSize(Size clientSize)\r\n   
    at System.Windows.Forms.Label.GetBordersAndPadding()\r\n   
    at System.Windows.Forms.Label.GetPreferredSizeCore(Size proposedConstraints)\r\n   
    at System.Windows.Forms.Control.GetPreferredSize(Size proposedSize)\r\n   
    at System.Windows.Forms.Label.GetPreferredSize(Size proposedSize)\r\n   
    at System.Windows.Forms.Control.get_PreferredSize()\r\n   
    at System.Windows.Forms.Label.AdjustSize()\r\n   
    at System.Windows.Forms.Label.OnTextChanged(EventArgs e)\r\n   
    at System.Windows.Forms.Control.set_Text(String value)\r\n   
    at System.Windows.Forms.Label.set_Text(String value)\r\n   
    at MyApp.MyAppToolbar.<TimeUpdater>b__0() in PATH\\TO\\FILE.cs:line 133\r\n   
    at MyApp.Utilities.InvokeIfRequired(Control control, MethodInvoker action) in PATH\\TO\\FILE.cs:line 34\r\n  MyApp.MyAppToolbar.TimeUpdater() in PATH\\TO\\FILE.cs:line 131\r\n   
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state)\r\n   
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n   
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n   
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n   
    at System.Threading.ThreadHelper.ThreadStart()

有人能指出我在正确的方向吗?

2 个答案:

答案 0 :(得分:2)

阅读InvokeRequired上的文档,您可以看到它尚未创建控件的句柄时返回false。文档说明您需要先检查IsHandleCreated的值。

还有一个关于销毁时间的问题,正如汉斯在上面所述,所以你可能想要检查控件是否已经在内部正确的线程时被处理。

另一种方法是在控件完全加载时启动后台线程,但这又使InvokeIfRequired不是通用工具。

答案 1 :(得分:0)

嗨sherlock我认为这会有所帮助 {{3P>