我正在创建一个应用程序,由于某种原因,当我点击按钮时,我必须启动一个新表单,同时在google文档中创建一个新文档。 我已经成功实现了上述功能,但是当应用程序忙于在谷歌文档中创建新文档时,新加载的表单的UI冻结了。 我在某处读到,如果我使用多线程,这可以避免。 所以现在我想问我应该创建两个线程,其中一个我应该放置代码来创建新表单,另一个我应该放置代码在google doc中创建一个文档。 或者我应该在线程上创建我应该放置代码来创建新的google doc并让新表单创建代码在主进程中? 另外,在已经编写的代码中实现线程的最简单方法是什么?如果可能的话,请提供一些参考阅读材料。
答案 0 :(得分:6)
你实际上有很多选择。
(1) BackgroundWorker。如果你真的想要在WinForms中进行异步工作的最简单的编程模型,那就是这个。它通常用于执行一些异步任务并报告进度,但如果您不需要,则不必报告进度。
(2)基于事件的异步模式。如果你想制作一个完整的组件来执行某些异步任务,完全控制报告进度和你自己的自定义事件,那么这是一种方式去做吧。这也有助于您了解线程而不是BackgroundWorker。因为我是一个视觉人物,I created a full video presentation on how to do just this with WinForms。
(3)任务并行库。您可以将TPL与WinForms一起使用,我写了very detailed blog post on how to do just that here。
(4)异步和等待。请注意,这需要.NET 4.5,C#5.0和C#5.0编译器仅包含在Visual Studio 11中,Visual Studio 11现在仅在BETA中。 However, I also have a full blog post on how to do just this
(5)带有线程的ISynchronizedInvoke。这是另一个选项,I also have a full blog about。
这取决于您选择哪种方法。我的建议是简要地看一下每个方法,然后选择一种方法,根据主题对你的感受,或者哪种方法最符合你的要求。
答案 1 :(得分:2)
您可以使用多种技术来完成您的要求,但我会建议使用任务并行库(TPL)(或BackgroundWorker
)。
创建/启动新表单的开销很小(在大多数情况下),因此在我看来,您应该在UI线程上启动表单,并在后台线程上创建Google Doc。所以使用TPL你会有类似的东西(非常基本的例子)
// In click event.
MyForm newForm = new MyForm();
newForm.Show();
Task googleDocTask = Task.Factory.StartNew(() =>
{
// Do your stuff with Google Docs.
// Note you cannot access the UI thread from within this delegate.
});
有关C#中线程的精彩讨论,请参阅Joseph Albahari's page on threading。
有关TPL的更多信息和相当完整的介绍,请参阅here。
我希望这会有所帮助。
答案 2 :(得分:2)
只需创建一个线程。我建议使用BackgroundWorker。他们非常直接。
把它放在班级的顶端:
private BackgroundWorker googleDocWorker = new BackgroundWorker();
将它放在构造函数中:
googleDocWorker.DoWork += new DoWorkEventHandler(googleDocWorker_DoWork);
googleDocWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(googleDocWorker_RunWorkerCompleted);
将这些方法放在你的班级中:
void googleDocWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// You can use this to alert you that the google doc is created.
}
void googleDocWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Create google doc here.
}
调用此方法开始创建google doc:
googleDocWorker.RunWorkerAsync();
现在,如果您需要将一些数据传递给BackgroundWorker,您可以传递任何您想要的内容。您可以使用对象数组传入字符串,甚至是不同类型的多个对象。这是一个发送多个对象的示例:
googleDocWorker.RunWorkerAsync(new object[] { "doc name", contents });
现在,这意味着他们必须在_DoWork方法中处理:
void googleDocWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Create google doc here.
object[] args = (object[])e.Argument;
String docName = (string)args[0];
SomeClass contents = (SomeClass)args[1];
}
假设您在创建文档后,想要将URL发送回刚刚创建的文档,您只需将其传递回_DoWork方法的_RunWorkerCompleted方法:
void googleDocWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Create google doc here.
...
e.Result = myURL;
}
在RunWorkerCompleted方法中获取URL后,它与DoWork方法几乎相同。
void googleDocWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// You can use this to alert you that the google doc is created.
String docURL = (String)e.Result;
}
希望有所帮助! (:
答案 3 :(得分:0)
IMHO。你应该只创建一个你将制作谷歌文档的线程(所以你将有两个线程)。
答案 4 :(得分:0)
最简单的方法是使用BackgroundWorker或使用ThreadPool。如果您的主UI在其他任务完成时并不在意,那么Threadpool会更简单。