如何让我的主 code/form 等待另一个 class' 函数在 C# 中完成,而不冻结?
How can I make my main code/form to wait for another class' function to finish in C#, without any freezing?
所以我有一个从 SQL 中提取 string/url 的代码,然后我的代码是这样的:
WebScrape browser1 = new WebScrape();
browser1.StartBrowser(weblink);
richTextBox1.Text = browser1.wholeText;
WebScrape 是一个包含浏览器的 class,StartBrowser 启动它并将其导航到 url/weblink,然后在文档完成时更新 "wholeText" 值。
这是 StartBrowser:
public void StartBrowser(string address)
{
url = address;
wb = new WebBrowser();
wb.DocumentCompleted += Web_DocumentCompleted;
wb.ScriptErrorsSuppressed = true;
Navigate(url);
}
转到我的导航功能进行更新url
private void Navigate(String address)
{
if (String.IsNullOrEmpty(address)) return;
if (address.Equals("about:blank")) return;
if (!address.StartsWith("http://") && !address.StartsWith("https://"))
{
address = "http://" + address;
}
try
{
wb.Navigate(new Uri(address));
}
catch (System.UriFormatException)
{
return;
}
}
然后当 WebDocument 完成时我想要的变量被分配,如下所示:
private void Web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
htmlCode = wb.Document;
wb.Dispose();
wholeText = getTexts();
plainText = splitText();
numberOfWords = plainText.Length;
webLinks = getLinks();
imageLinks = getImages();
imageSizes = getImageSize();
}
这里的问题是,在 StartBrowser() 之后,它直接进入 richTextBox1.Text 而不是等待 class 自己完成它正在做的事情。
如何让我的代码等待我的 class 完成导航并在不冻结 UI/Form 的情况下执行此操作?
updates the "wholeText" value WHEN Document is completed.
那为什么不把 richTextBox1.Text = browser1.wholeText;在你的 Web_DocumentCompleted 方法中?
private void Web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
htmlCode = wb.Document;
wb.Dispose();
wholeText = getTexts();
plainText = splitText();
numberOfWords = plainText.Length;
webLinks = getLinks();
imageLinks = getImages();
imageSizes = getImageSize();
richTextBox1.Text = browser1.wholeText;
}
这应该可以解决第一个问题,但所有这些都在主线程上运行。
你可以这样做:
Thread backgroundThread = new Thread(new ThreadStart(new Action(() => browser1.StartBrowser(weblink))));
backgroundThread.Start();
这应该将您的 StartBrowser 方法移动到一个新线程,然后是您的 Web_DocumentCompleted 事件。我对此不是 100%,所以也许有人能比我更清楚地解决这个问题。请记住调用 UI 元素,因为您无法从另一个线程访问它们。
直接的方法是为您的 WebScrape
提供回调函数,以便在文档解析完成后调用:
public class WebScrape() {
// ...
public Action DocumentCompletedCallback;
}
然后在文档完成时调用它:
private void Web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// ...
DocumentCompletedCallback?.Invoke();
}
然后你这样使用它:
WebScrape browser1 = new WebScrape();
browser1.DocumentCompletedCallback = () => {
// may need to return to UI thread here via Invoke
richTextBox1.Text = browser1.wholeText;
};
browser1.StartBrowser(weblink);
如有必要,您可以使用 async\await 和任务(更多 "modern" 方式)做类似的事情。
所以我有一个从 SQL 中提取 string/url 的代码,然后我的代码是这样的:
WebScrape browser1 = new WebScrape();
browser1.StartBrowser(weblink);
richTextBox1.Text = browser1.wholeText;
WebScrape 是一个包含浏览器的 class,StartBrowser 启动它并将其导航到 url/weblink,然后在文档完成时更新 "wholeText" 值。
这是 StartBrowser:
public void StartBrowser(string address)
{
url = address;
wb = new WebBrowser();
wb.DocumentCompleted += Web_DocumentCompleted;
wb.ScriptErrorsSuppressed = true;
Navigate(url);
}
转到我的导航功能进行更新url
private void Navigate(String address)
{
if (String.IsNullOrEmpty(address)) return;
if (address.Equals("about:blank")) return;
if (!address.StartsWith("http://") && !address.StartsWith("https://"))
{
address = "http://" + address;
}
try
{
wb.Navigate(new Uri(address));
}
catch (System.UriFormatException)
{
return;
}
}
然后当 WebDocument 完成时我想要的变量被分配,如下所示:
private void Web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
htmlCode = wb.Document;
wb.Dispose();
wholeText = getTexts();
plainText = splitText();
numberOfWords = plainText.Length;
webLinks = getLinks();
imageLinks = getImages();
imageSizes = getImageSize();
}
这里的问题是,在 StartBrowser() 之后,它直接进入 richTextBox1.Text 而不是等待 class 自己完成它正在做的事情。
如何让我的代码等待我的 class 完成导航并在不冻结 UI/Form 的情况下执行此操作?
updates the "wholeText" value WHEN Document is completed.
那为什么不把 richTextBox1.Text = browser1.wholeText;在你的 Web_DocumentCompleted 方法中?
private void Web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
htmlCode = wb.Document;
wb.Dispose();
wholeText = getTexts();
plainText = splitText();
numberOfWords = plainText.Length;
webLinks = getLinks();
imageLinks = getImages();
imageSizes = getImageSize();
richTextBox1.Text = browser1.wholeText;
}
这应该可以解决第一个问题,但所有这些都在主线程上运行。
你可以这样做:
Thread backgroundThread = new Thread(new ThreadStart(new Action(() => browser1.StartBrowser(weblink))));
backgroundThread.Start();
这应该将您的 StartBrowser 方法移动到一个新线程,然后是您的 Web_DocumentCompleted 事件。我对此不是 100%,所以也许有人能比我更清楚地解决这个问题。请记住调用 UI 元素,因为您无法从另一个线程访问它们。
直接的方法是为您的 WebScrape
提供回调函数,以便在文档解析完成后调用:
public class WebScrape() {
// ...
public Action DocumentCompletedCallback;
}
然后在文档完成时调用它:
private void Web_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// ...
DocumentCompletedCallback?.Invoke();
}
然后你这样使用它:
WebScrape browser1 = new WebScrape();
browser1.DocumentCompletedCallback = () => {
// may need to return to UI thread here via Invoke
richTextBox1.Text = browser1.wholeText;
};
browser1.StartBrowser(weblink);
如有必要,您可以使用 async\await 和任务(更多 "modern" 方式)做类似的事情。