在newThread()中创建控件时在正确线程上调用方法我在newThread()中创建了一个新的WebBrowser()控件。我遇到的问题是,当从主线程调用我的WebBrowser的委托时,调用是在主线程上进行的。我希望这发生在browserThread上。私有静态WebBrowserdefaultApiClient=null;委托voidDocumentNavigator(stringurl);privateWebApi(){//创建一个负责调用API的新线程。ThreadbrowserThread=newThread(()=>{defaultApiClient=newWebBrowser();//设置我们的代表documentNavigatorDelegate=newDocumentNavigator(defaultApiClient.Navigate);//匿名事件处理程序defaultApiClient.DocumentCompleted+=(objectsender,WebBrowserDocumentCompletedEventArgse)=>{//做其他事情};Application.Run();});browserThread.SetApartmentState(ApartmentState.STA);browserThread.Start();}DocumentNavigatordocumentNavigatorDelegate=null;privatevoidEnsureInitialized(){//由于某些原因,这总是返回“false”if(defaultApiClient.InvokeRequired){//如果我跳到这个调用//并在System.Windows.Forms.dll!System上放置一个断点.Windows.Forms.WebBrowser.Navigate(stringurlString,stringtargetFrameName,byte[]postData,stringadditionalHeaders)//我发现我的调用是在“主线程”中完成的。我希望这是在“browserThread”中完成的,而不是objectresult=defaultApiClient.Invoke(documentNavigatorDelegate,WebApiUrl);我尝试了无数种方法来调用此方法://在主线程上调用(如预期的那样)defaultApiClient.Navigate(WebApiUrl);//在主线程上调用defaultApiClient.Invoke(documentNavigatorDelegate,WebApiUrl);//在主线程上调用defaultApiClient.BeginInvoke(documentNavigatorDelegate,WebApiUrl);//在主线程上调用documentNavigatorDelegate.Invoke(WebApiUrl);//调用随机工作线程documentNavigatorDelegate.BeginInvoke(WebApiUrl,newAsyncCallback((IAsyncResultresult)=>{....}),null);更新让我分解我的最终目标以使事情更清楚:我必须使用WebBrowser.Document.InvokeScript()进行调用,但只有在我调用WebBrowser.Navigate()之后WebBrowser.Navigate()才会加载文档WebBrowser.DocumentComplete事件触发器基本上,在DocumentComplete触发之前我无法调用InvokeScript()...我想等待文档加载(阻止我的调用者)以便我可以调用InvokeScript并同步返回我的结果。基本上我需要等待我的文档完成,我想要这样做的方式是使用AutoResetEvent()类,当DocumentComplete被触发时我会触发它......我需要所有这些东西在一个单独的线程中发生。我看到的另一个选择是做这样的事情:privateboolinitialized=false;privatevoidEnsureInitialized(){defaultApiClient.Navigate(WebApiUrl);while(!initialized){Thread.Sleep(1000);//这个块在技术上是行不通的}}privatevoiddefaultApiClient_DocumentComplete(objectsender,WebBrowserDocumentCompletedEventArgse){initialized=true;这是设计使然。创建控件的Handle属性需要控件的InvokeRequired/BeginInvoke/Invoke成员。这是它确定要调用哪个特定线程的主要方式。但这不会在您的代码中发生,通常仅当您将控件添加到父级的Controls集合并使用Show()显示父级时,才会创建句柄。也就是说,宿主窗口实际上是为浏览器创建的。这些都不会发生在您的代码中,因此Handle仍然是IntPtr.Zero并且InvokeRequired返回false。这其实不是问题。WebBrowser类很特殊,它是底层的COM服务器。COM自己处理线程细节,而不是将其留给程序员,这与.NET的工作方式非常不同。它自动编组对其Navigate()方法的调用。这是完全自动的,不需要任何帮助。COM服务器的好客之家就是所需要的全部,您可以通过创建STA线程并使用Application.Run()抽出消息循环来创建一个。它是COM用来执行自动编组的消息循环。所以你可以简单地在主线程上调用Navigate()而不会出现任何问题。DocumentCompleted事件仍会在辅助线程上触发,您可以愉快地在该线程上修改Document。不知道为什么这是一个问题,它应该一切正常。也许您只是对其行为感到困惑。如果没有,那么这个答案可以帮助您找到更通用的解决方案。不要太害怕nay-says太多btw,在工作线程上显示UI充满陷阱,但你永远不会在这里显示任何UI,也永远不会创建窗口。这个答案是基于更新的问题和评论:基本上我需要等待我的文档完成,我想要这样做的方式是使用AutoResetEvent()类,当DocumentComplete被触发时我会触发...我需要所有这些东西在一个单独的线程中发生。...我知道主用户界面将被冻结。这只会在应用程序的生命周期内发生一次(在初始化时)。我正试图找到另一种方法来完成我想要完成的事情。我认为您不应该为此使用单独的线程。您可以禁用UI(例如,使用模态“请稍候...”对话框)并在主UI线程上执行与WebBrowser相关的工作。总之,下面的代码显示了如何在单独的STA线程上驱动WebBrowser对象。它基于我最近发布的相关答案,但与.NET4.0兼容。使用.NET4+,您不再需要使用AutoResetEvent等低级同步原语。使用TaskCompletionSource,它允许将结果和可能的异常传播到操作的消费者端。以上就是C#学习教程:在newThread()中创建控件时,在正确的线程上调用方法,共享所有内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多加关注——usingusingSystem.Threading;使用System.Threading.Tasks;使用System.Windows.Forms;namespaceWinFroms_21790151{publicpartialclassMainForm:Form{publicMainForm(){InitializeComponent();this.Load+=MainForm_Load;}voidMainForm_Load(objectsenderLoad,EventArgseLoad){using(varapartment=newMessageLoopApartment()){//在一个单独的线程上创建WebBrowser,它有自己的消息循环varwebBrowser=apartment.调用(()=>newWebBrowser());//导航并等待结果varbodyHtml=apartment.Invoke(()=>{WebBrowserDocumentCompletedEventHandlerhandler=null;varpageLoadedTcs=newTaskCompletionSource();handler=(s,e)=>{try{webBrowser.DocumentCompleted-=handler;pageLoadedTcs.SetResult(webBrowser.Document.Body.InnerHtml);}catch(异常前){pageLoadedTcs.SetException(ex);}};webBrowser.DocumentCompleted+=处理程序;webBrowser.Navigate("http://example.com");//返回任务returnpageLoadedTcs.Task;})。结果;MessageBox.Show("正文内容:n"+bodyHtml);//执行一些JavaScriptvardocumentHtml=apartment.Invoke(()=>{//必须至少存在一个脚本元素才能使eval生效varscriptElement=webBrowser.Document.CreateElement("script");webBrowser.Document.Body.AppendChild(scriptElement);//注入并运行一些脚本varscriptResult=webBrowser.Document.InvokeScript("eval",new[]{"(function(){returndocument.documentElement.outerHTML;})();"});返回scriptResult.ToString();});MessageBox.Show("文件内容:n"+documentHtml);//处理webBrowserapartment.Invoke(()=>webBrowser.Dispose());网络浏览器=空;}}//MessageLoopApartment公共类MessageLoopApartment:IDisposable{Thread_thread;//STA线程TaskScheduler_taskScheduler;//STA线程的任务调度器publicTaskSchedulerTask调度程序{得到{返回_taskScheduler;}}///MessageLoopApartment构造函数publicMessageLoopApartment(){vartcs=newTaskCompletionSource();//启动一个STA线程并获得一个任务调度器_thread=newThread(startArg=>{EventHandleridleHandler=null;idleHandler=(s,e)=>{//只处理一次Application.Idle//返回任务调度程序tcs.SetResult(TaskScheduler.FromCurrentSynchronizationContext());};//只处理一次Application.Idle//以确保我们在消息循环中//并且SynchronizationContext已正确安装Application.Idle+=idleHandler;Application.Run();});_thread.SetApartmentState(ApartmentState.STA);_thread.IsBackground=true;_thread.Start();_taskScheduler=tcs.Task.Result;}///关闭STA线程publicvoidDispose(){if(_taskScheduler!=null){vartaskScheduler=_taskScheduler;_taskScheduler=null;//执行Application.ExitThSTA线程上的read()Task.Factory.StartNew(()=>Application.ExitThread(),CancellationToken.None,TaskCreationOptions.None,taskScheduler).Wait();_thread.Join();_线程=空;}}///Task.Factory.StartNew包装器publicvoidInvoke(Actionaction){}publicTResultInvoke(Funcaction){returnTask.Factory.StartNew(action,CancellationToken.None,TaskCreationOptions.None,_taskScheduler).Result;}publicTaskRun(Actionaction,CancellationTokentoken){returnTask.Factory.StartNew(action,token,TaskCreationOptions.None,_taskScheduler);}publicTaskRun(Funcaction,CancellationTokentoken){returnTask.Factory.StartNew(action,token,TaskCreationOptions.None,_taskScheduler);}publicTaskRun(Funcaction,CancellationTokentoken){returnTask.Factory.StartNew(action,token,TaskCreationOptions.None,_taskScheduler).Unwrap();}publicTaskRun(Func>action,CancellationTokentoken){returnTask.Factory.StartNew(action,token,TaskCreationOptions.None,_taskScheduler).Unwrap();}}}}侵权请点右联系管理员删除如转载请注明出处:
