.net C++/CLI WinForms:BeginInvoke错误

.net C++/CLI WinForms:BeginInvoke错误,.net,multithreading,winforms,c++-cli,begininvoke,.net,Multithreading,Winforms,C++ Cli,Begininvoke,我无法找出此错误的原因: 在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke 这是我的(剥离)代码: private: delegate void MyDelegate(Object^ openFileDialog1); ListView^ myDelegate; private: void import_links(Object^ openFileDialog1) { myDelegate = (gcnew System::Windows::For

我无法找出此错误的原因:

在创建窗口句柄之前,无法对控件调用Invoke或BeginInvoke

这是我的(剥离)代码:

private: delegate void MyDelegate(Object^ openFileDialog1);
ListView^ myDelegate;

private: void import_links(Object^ openFileDialog1) {
            myDelegate = (gcnew System::Windows::Forms::ListView());
            myDelegate->BeginInvoke( gcnew MyDelegate( this, &Form1::import_links ), openFileDialog1);

            //do some work here
}
private: System::Void Import_LinkClicked(System::Object^  sender, System::Windows::Forms::LinkLabelLinkClickedEventArgs^  e) {
        OpenFileDialog^ openFileDialog1 = gcnew OpenFileDialog;

        if ( openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK )
        {
            Thread^ importThread = gcnew Thread(gcnew ParameterizedThreadStart(this,&Form1::import_links));
            importThread->Start(openFileDialog1);
        }
    }
请告诉我解决办法

        myDelegate = (gcnew System::Windows::Forms::ListView());
这种说法的基本问题是:

  • 它不是委托,而是ListView对象
  • 控件与创建它们的线程有很强的关联。像您这样在工作线程上创建控件永远都是不正确的
  • 控件需要父控件才能显示和使用,但它没有父控件
  • 控件要求线程运行dispatcher循环,以便获取消息。这样的线程必须调用Application::Run()。您的工作线程不可用
  • 控件的基础窗口是在需要显示时延迟创建的。因为它没有父窗口,也不可见,所以还不需要创建窗口。因此,正如异常告诉您的那样,它没有有效的句柄属性
  • BeginInvoke()确保调用的代码在拥有该控件的线程上运行。由于拥有它的是工作线程,因此BeginInvoke()永远不能实际调用另一个线程
您已经有了对正确线程所拥有的对象的引用。这是
这个
。因此,正确的代码如下所示:

void import_links(Object^ openFileDialog1) {
    if (this->InvokeRequired) {
       this->BeginInvoke( gcnew MyDelegate( this, &Form1::import_links ), openFileDialog1);
    }
    else {
        //do some work here
    }
}
但请注意最终的谬误,您创建了一个工作线程,它所做的唯一事情就是调用
this->BeginInvoke()
。这需要几分之一微秒。创建一个线程来完成这么少的工作从来没有用过

重构您的代码,使用BackgroundWorker。让它的DoWork事件处理程序只做昂贵的事情,比如导入文件。让它的RunWorkerCompleted事件只执行UI线程上需要执行的操作,例如显示导入结果和隐藏“我正在处理”通知

这种说法的基本问题是:

  • 它不是委托,而是ListView对象
  • 控件与创建它们的线程有很强的关联。像您这样在工作线程上创建控件永远都是不正确的
  • 控件需要父控件才能显示和使用,但它没有父控件
  • 控件要求线程运行dispatcher循环,以便获取消息。这样的线程必须调用Application::Run()。您的工作线程不可用
  • 控件的基础窗口是在需要显示时延迟创建的。因为它没有父窗口,也不可见,所以还不需要创建窗口。因此,正如异常告诉您的那样,它没有有效的句柄属性
  • BeginInvoke()确保调用的代码在拥有该控件的线程上运行。由于拥有它的是工作线程,因此BeginInvoke()永远不能实际调用另一个线程
您已经有了对正确线程所拥有的对象的引用。这是
这个
。因此,正确的代码如下所示:

void import_links(Object^ openFileDialog1) {
    if (this->InvokeRequired) {
       this->BeginInvoke( gcnew MyDelegate( this, &Form1::import_links ), openFileDialog1);
    }
    else {
        //do some work here
    }
}
但请注意最终的谬误,您创建了一个工作线程,它所做的唯一事情就是调用
this->BeginInvoke()
。这需要几分之一微秒。创建一个线程来完成这么少的工作从来没有用过

重构您的代码,使用BackgroundWorker。让它的DoWork事件处理程序只做昂贵的事情,比如导入文件。让它的RunWorkerCompleted事件只执行UI线程上需要执行的操作,例如显示导入结果和隐藏“我正在处理”通知

这种说法的基本问题是:

  • 它不是委托,而是ListView对象
  • 控件与创建它们的线程有很强的关联。像您这样在工作线程上创建控件永远都是不正确的
  • 控件需要父控件才能显示和使用,但它没有父控件
  • 控件要求线程运行dispatcher循环,以便获取消息。这样的线程必须调用Application::Run()。您的工作线程不可用
  • 控件的基础窗口是在需要显示时延迟创建的。因为它没有父窗口,也不可见,所以还不需要创建窗口。因此,正如异常告诉您的那样,它没有有效的句柄属性
  • BeginInvoke()确保调用的代码在拥有该控件的线程上运行。由于拥有它的是工作线程,因此BeginInvoke()永远不能实际调用另一个线程
您已经有了对正确线程所拥有的对象的引用。这是
这个
。因此,正确的代码如下所示:

void import_links(Object^ openFileDialog1) {
    if (this->InvokeRequired) {
       this->BeginInvoke( gcnew MyDelegate( this, &Form1::import_links ), openFileDialog1);
    }
    else {
        //do some work here
    }
}
但请注意最终的谬误,您创建了一个工作线程,它所做的唯一事情就是调用
this->BeginInvoke()
。这需要几分之一微秒。创建一个线程来完成这么少的工作从来没有用过

重构您的代码,使用BackgroundWorker。让它的DoWork事件处理程序只做昂贵的事情,比如导入文件。让它的RunWorkerCompleted事件只执行UI线程上需要执行的操作,例如显示导入结果和隐藏“我正在处理”通知

这种说法的基本问题是:

  • 它不是委托,而是ListView对象
  • 控件与创建它们的线程有很强的关联。像您这样在工作线程上创建控件永远都是不正确的
  • 控件需要父控件才能显示和使用,但它没有父控件
  • 控件要求线程运行dispatcher循环,以便获取消息。这样的线程必须调用Application::Run()。您的工作线程不可用
  • 控件的基础窗口是在需要显示时延迟创建的。自从