Нужно руководство о том, как сделать функцию асинхронной / неблокирующей - PullRequest
1 голос
/ 23 ноября 2010

Предположим, у меня есть класс HttpHelper с GetResponseStream(), который загружает данные запроса, показывающие ход выполнения событий StatusChanged & ProgressChanged.

public MemoryStream GetResponseStream() {
    ...
    Status = Statuses.Uploading; // this doesn't raise StatusChanged
    // write to request stream
    ... // as I write to stream, ProgressChanged doesn't get raised too
    Status = Statuses.Downloading; // this too
    // write to response stream
    ... // same here
    Status = Statuses.Idle; // this runs ok. Event triggered, UI updated
}

Код @ pastebin . GetRequestStream() в строке 76. Сам класс работает нормально, за исключением того, что использующий класс должен вызывать его, как показано ниже

HttpHelper helper = new HttpHelper("http://localhost/uploadTest.php");
helper.AddFileHeader("test.txt", "test.txt", "text/plain", File.ReadAllBytes("./test.txt"));
helper.StatusChanged += (s, evt) =>
{
    _dispatcher.Invoke(new Action(() => txtStatus.Text = helper.Status.ToString()));

    if (helper.Status == HttpHelper.Statuses.Idle || helper.Status == HttpHelper.Statuses.Error)
        _dispatcher.Invoke(new Action(() => progBar.IsIndeterminate = false));

    if (helper.Status == HttpHelper.Statuses.Error)
        _dispatcher.Invoke(new Action(() => txtStatus.Text = helper.Error.Message));
};
helper.ProgressChanged += (s, evt) =>
{
    if (helper.Progress.HasValue)
        _dispatcher.Invoke(new Action(() => progBar.Value = (double)helper.Progress));
    else
        _dispatcher.Invoke(new Action(() => progBar.IsIndeterminate = true));
};
Task.Factory.StartNew(() => helper.GetResponseString());

Если бы я позвонил в класс, используя

helper.GetResponseString();

Тогда сам класс будет работать, но события, похоже, не инициируются. Я думаю, что это связано с тем, что поток пользовательского интерфейса заблокирован. Как я могу перекодировать класс так, чтобы его было легче / чище использовать классу без всяких вещей _dispatcher & Task.

Кроме того, я хотел бы знать наверняка, что приводит к тому, что события / пользовательский интерфейс не обновляются. Даже если код является синхронным, не может ли он в любом случае запустить измененное свойство / events, его после чтения / записи?

1 Ответ

2 голосов
/ 23 ноября 2010

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

...