2009-07-09 47 views
1

我的應用程序通常使用WebRequest從網頁中獲取數據,但在獲取數據時不可能點擊按鈕等。我明白我必須使用線程/背景工作,但我無法讓它正常工作;它不會使GUI更具可響應性。GUI在獲取數據時沒有響應

我想申請某種形式的線程上,使得它停止讓我的應用程序不能響應代碼:

public string SQLGet(string query) 
{ 
    string post = "q=" + query; 
    WebRequest request = WebRequest.Create("http://test.com"); 
    request.Timeout = 20000; 
    request.Method = "POST"; 
    byte[] bytes = Encoding.UTF8.GetBytes(post); 
    request.ContentType = "application/x-www-form-urlencoded"; 
    request.ContentLength = bytes.Length; 

    Stream requestStream = request.GetRequestStream(); 
    requestStream.Write(bytes, 0, bytes.Length); 
    requestStream.Close(); 

    WebResponse response = request.GetResponse(); 
    requestStream = response.GetResponseStream(); 
    StreamReader reader = new StreamReader(requestStream); 
    string ret = reader.ReadToEnd(); 

    reader.Close(); 
    requestStream.Close(); 
    response.Close(); 

    return ret; 
} 

編輯:謝謝,LC,我試過很相似的東西。但是我使用這種背景工作的問題在於:我怎麼得到queryResult回到函數調用(在我的情況下SQLGet,並在你的情況)StartQuery?

在我的例子中,返回的字符串將被用作void的字符串被調用的局部變量。

並且可能有很多查詢在同一時間,所以我不想冒險分配給一個全局變量。

+0

請張貼代碼,你啓動一個線程運行`SQLGet`。 – 2009-07-09 03:51:33

+0

目前我沒有使用線程,因爲我不知道如何以他們想要的方式來實現它們。這就是我尋求幫助的原因。 – Phoexo 2009-07-09 07:40:14

+0

更新我的答案以符合您的修改。 – 2009-07-09 15:09:13

回答

5

這裏是因爲它適用於你的代碼如何使用BackgroundWorker一個簡單的例子:

private void StartQuery(string query) 
{ 
    BackgroundWorker backgroundWorker1 = new BackgroundWorker(); 
    backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); 
    backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted); 
    backgroundWorker1.RunWorkerAsync(query); 
} 

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    e.Result = SQLGet((string)e.Argument); 
} 

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    queryResult = (string)e.Result; 
} 

您也可能希望允許取消,提供錯誤的詳細信息,或提供可靠的反饋,因爲它獲取數據。看看on the MSDN page的例子來了解更多細節。

查詢結果將顯示在BackgroundWorker.RunWorkerCompleted事件中e.Result(在本例中,我將它作爲實例變量存儲)。如果您要同時運行其中的許多內容,則需要一種方法來區分哪個查詢是哪個。所以你不應該只將一個字符串傳遞給該方法。拿這個例子:

private int NextID = 0; 

private struct QueryArguments 
{ 
    public QueryArguments() 
    { 
    } 

    public QueryArguments(int QueryID, string Query) 
     : this() 
    { 
     this.QueryID = QueryID; 
     this.Query = Query; 
    } 

    public int QueryID { get; set; } 
    public string Query { get; set; } 
    public string Result { get; set; } 
} 

private int StartQuery(string query) 
{ 
    QueryArguments args = new QueryArguments(NextID++, query); 

    BackgroundWorker backgroundWorker1 = new BackgroundWorker(); 
    backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); 
    backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted); 
    backgroundWorker1.RunWorkerAsync(args); 

    return args.QueryID; 
} 

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    QueryArguments args = (QueryArguments)e.Argument; 
    args.Result = SQLGet(args.Query); 
    e.Result = args; 
} 

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    QueryArguments args = (QueryArguments)e.Result; 
    //args.Result contains the result 

    //do something 
} 
2

這是一個快速的解決方案,應該很容易從你的需要中得到它。

using System; 
using System.ComponentModel; 
using System.IO; 
using System.Net; 
using System.Text; 

namespace ConsoleApplication5 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      BackgroundWorker b = new BackgroundWorker(); 
      b.DoWork += new DoWorkEventHandler(b_DoWork); 
      b.RunWorkerCompleted += new RunWorkerCompletedEventHandler(b_RunWorkerCompleted); 
      b.RunWorkerAsync("My Query"); 

      while(b.IsBusy) 
      { 

      } 
      Console.ReadLine(); 
     } 

     static void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
     { 
      if(e.Result is string) 
      { 
       Console.WriteLine((string)e.Result); 
      } 
     } 

     static void b_DoWork(object sender, DoWorkEventArgs e) 
     { 
      if (e.Argument is string) 
      { 
       string post = "q=" + (string) e.Argument; 
       WebRequest request = WebRequest.Create("http://test.com"); 
       request.Timeout = 20000; 
       request.Method = "POST"; 
       byte[] bytes = Encoding.UTF8.GetBytes(post); 
       request.ContentType = "application/x-www-form-urlencoded"; 
       request.ContentLength = bytes.Length; 
       Stream requestStream = request.GetRequestStream(); 
       requestStream.Write(bytes, 0, bytes.Length); 
       requestStream.Close(); 
       WebResponse response = request.GetResponse(); 
       requestStream = response.GetResponseStream(); 
       StreamReader reader = new StreamReader(requestStream); 
       string ret = reader.ReadToEnd(); 
       reader.Close(); 
       requestStream.Close(); 
       response.Close(); 
       e.Result = ret; 
      } 
     } 
    } 
} 
3

BackgroundWorker是一個很好的解決方案,有一些內置的支持取消和進度。您也可以僅使用HttpWebRequest.BeginGetResponse而不是GetResponse來啓動異步Web請求操作。這最終是非常簡單的,你可以設置一個進度回調。

對於你想要做什麼確切的例子,請參閱:

Using HttpWebRequest for Asynchronous Downloads