2009-07-09 13 views
1

私のアプリケーションは、WebRequestを使用してWebページからデータを取得することがよくありますが、取得中にボタンなどをクリックすることはできません。スレッド/バックグラウンドワーカーを使用しなければならないことを理解しましたが、正しく動作させることはできません。 GUIの応答性は向上しません。データの取得中にGUIが応答しない

それは私のアプリケーションunrespondingを作る停止するように私は、上のスレッドのいくつかの種類を適用したいコード:

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、私はそれにかなり類似した何かをしようとした、ありがとう。しかし、そのようなバックグラウンド労働者を使用して私の問題は、どのようにして(私の場合はSQLGetで、あなたのケースでは)StartQueryを呼び出す関数にqueryResultを戻すのですか?

私の例では、返された文字列は、文字列が内部で呼び出されたvoidのローカル変数として使用されます。

同時に多数のクエリが存在する可能性があるので、グローバル変数に割り当てることを危険にさらしたくありません。ここで

+0

あなたがスレッドを開始し、 'SQLGet'を実行するコードを投稿してください。 –

+0

スレッドを使用していない現時点では、私はそれらを実装する方法がわからないので、スレッドを使用します。それが私が助けを求めている理由です。 – Phoexo

+0

あなたの編集に合わせて私の答えが更新されました。 –

答えて

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 
} 
+0

ありがとうございます。質問が更新されました。 – Phoexo

+0

また、 Dispose()と同じ機能をClose()していないのですか? – Phoexo

+0

@PhoexoあなたはDispose()を呼び出すClose()について正しいです。私は常にIDisposablesを「使用」またはDispose()していますが、必要はありません(http://msdn.microsoft.com/en-us/library/system.io.stream.close.aspx)。混乱させて申し訳ありません。 –

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; 
      } 
     } 
    } 
} 
+0

whileループでApplication.DoEvents()呼び出しをしたくないですか?それ以外の場合は、別のスレッドで実行する必要はありません。 –

+0

コードのレイアウトとその動作をさらに詳しく示します。 – PostMan

3

BackgroundWorkerは良い解決策で、中止と進捗状況のサポートが組み込まれています。 GetResponseではなくHttpWebRequest.BeginGetResponseを使用して、非同期Webリクエスト操作を開始することもできます。これは非常に簡単になり、進行状況のコールバックを設定することができます。あなたが何をしようとしての正確例えば

、以下を参照してください

Using HttpWebRequest for Asynchronous Downloads

関連する問題