データをフェッチしながらGUIが応答しません
-
12-09-2019 - |
質問
私のアプリケーションは、多くの場合、WebRequestクラスを使用してWebページからデータをフェッチし、それはフェッチている間などのボタンをクリックすることはできません。私は、スレッド/ BackgroundWorkerのを使用する必要があることを理解しましたが、私はそれが正常に動作させることはできません。それは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、私はそれにかなり類似した何かをしようとしました。しかし、そのようBackgroundWorkerのを使用してと私の問題があります。どのように私は戻って(私の場合SQLGetで、そしてあなたのケースで)呼び出された関数にQueryResultではを得るのですかStartQuery?
私の例では、返される文字列は、文字列が内部に呼び出される内のローカル変数として使用されようとしています。
そして、そこに同時に多くのクエリであってもよいし、私はグローバル変数に代入危険にさらしたくありません。
解決
ここで 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;
}
また、キャンセルを許可するエラーの詳細を提供し、またはそれがデータをフェッチとして堅牢なフィードバックを提供することができます。 MSDNページにの例を見てみましょう詳細についてます。
クエリの結果は、(私はこの場合はインスタンス変数としてそれを保存した)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
}
他のヒント
のBackgroundWorkerはキャンセルと進歩のためのいくつかのビルトインサポートとの良好なソリューションです。また、単に非同期のWeb要求動作を開始するために、かなりのGetResponseより、HttpWebRequest.BeginGetResponseを使用することができます。これは非常にシンプルなってしまうと、あなたは進捗コールバックを設定することができます。
あなたが何をしようとしての正確なたとえば、参照してください。
ここでは簡単なソリューションです、あなたはそれから必要なものを取るために簡単にする必要があります。
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;
}
}
}
}