GUI не отвечает при получении данных - PullRequest
1 голос
/ 09 июля 2009

Мое приложение часто извлекает данные с веб-страницы с помощью WebRequest, но во время выборки невозможно нажимать кнопки и т. Д. Я понял, что я должен использовать потоки / фоновый работник, но я не могу заставить его работать должным образом; это не делает графический интерфейс более отзывчивым.

Код, к которому я хочу применить некоторую многопоточность, чтобы оно перестало отвечать на запросы моего приложения:

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?

В моем примере возвращенная строка будет использоваться как локальная переменная в пустоте, внутри которой вызывается строка.

И может быть много запросов одновременно, поэтому я не хочу рисковать назначением его глобальной переменной.

Ответы [ 3 ]

5 голосов
/ 09 июля 2009

Вот простой пример использования 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
}
3 голосов
/ 09 июля 2009

BackgroundWorker - хорошее решение с некоторой встроенной поддержкой отмены и прогресса. Вы также можете просто использовать HttpWebRequest.BeginGetResponse вместо GetResponse, чтобы инициировать асинхронную операцию веб-запроса. В конечном итоге это довольно просто, и вы можете настроить обратный вызов прогресса.

Точный пример того, что вы пытаетесь сделать, см .:

Использование HttpWebRequest для асинхронных загрузок

2 голосов
/ 09 июля 2009

Вот быстрое решение, должно быть легко взять то, что вам нужно.

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;
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...