4

I want to load image from the web on windows forms application, Everything is good and code works fine, but the problem is the app stop working until the loading goes to finish. I want to see and work with app without waiting to loading .

PictureBox img = new System.Windows.Forms.PictureBox();
var request = WebRequest.Create(ThumbnailUrl);

using (var response = request.GetResponse())
using (var stream = response.GetResponseStream())
{
    img.Image = Bitmap.FromStream(stream);
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
ara
  • 109
  • 2
  • 8
  • 1
    Time to research `BackgroundWorker` and `asnyc`. – Jonathon Reinhart Jun 11 '16 at 12:55
  • thank you , I search now – ara Jun 11 '16 at 12:56
  • Do it in a backgroundworker `dowork` event rather – Rahul Jun 11 '16 at 12:58
  • @Rahul , thank you, I going to search about backgroundworker dowork – ara Jun 11 '16 at 13:02
  • BackgroundWorker has fallen out of favor with async/await. If you are going to spend your time learning, may as well learn todays tech. – Crowcoder Jun 11 '16 at 13:04
  • I think this article can be useful: [Basics of Task](http://www.codeproject.com/Articles/189374/The-Basics-of-Task-Parallelism-via-C) – Thadeu Fernandes Jun 11 '16 at 14:17
  • 2
    `PictireBox` control supports loading images asynchronously itself and you don't need to use background worker or async/await. It also loads image from a url, so you don't need to use a web request. You can simply use `LoadAsync` methd or `ImageLocation` property of `PictureBox`. The value of `WaitOnLoad` property should be false which is default. See the answer below. – Reza Aghaei Jun 12 '16 at 00:57

2 Answers2

8

Here is the solution:

public async Task<Image> GetImageAsync(string url)
{
    var tcs = new TaskCompletionSource<Image>();
    Image webImage = null;
    HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
    request.Method = "GET";
    await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null)
        .ContinueWith(task =>
        {
            var webResponse = (HttpWebResponse) task.Result;
            Stream responseStream = webResponse.GetResponseStream();
            if (webResponse.ContentEncoding.ToLower().Contains("gzip"))
                responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
            else if (webResponse.ContentEncoding.ToLower().Contains("deflate"))
                responseStream = new DeflateStream(responseStream, CompressionMode.Decompress);

            if (responseStream != null) webImage = Image.FromStream(responseStream);
            tcs.TrySetResult(webImage);
            webResponse.Close();
            responseStream.Close();
        });
    return tcs.Task.Result;
}

Here is how to call the above solution:

PictureBox img = new System.Windows.Forms.PictureBox();
var result = GetImageAsync(ThumbnailUrl);
result.ContinueWith(task =>
{
    img.Image = task.Result;
});
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Yasser Bazrforoosh
  • 1,246
  • 10
  • 13
  • are you missing something like '**)**' , because the code doesn't work – ara Jun 11 '16 at 13:33
  • So thank you, it was fantastic, dameeeet garm yaser jan – ara Jun 11 '16 at 14:19
  • `PictireBox` control supports loading images asynchronously itself and you don't need to use background worker or async/await. You can simply use [`LoadAsync`](https://msdn.microsoft.com/en-us/library/ww2xzydc(v=vs.110).aspx) methd of `PictureBox`. – Reza Aghaei Jun 11 '16 at 14:39
  • @RezaAghaei Sometimes you have to receive the picture from a site which it needs to add a header and some cookies. Consenquently, you will be allowed to get the picture. – Yasser Bazrforoosh Jun 15 '16 at 05:54
  • @YasserBazrforoosh Yes. It would be useful for future readers if they have such requirement. The comment is just to inform readers of such built-in support in `PictureBox` for loading image asynchronously from a URL :) – Reza Aghaei Jun 15 '16 at 12:28
  • 1
    @YasserBazrforoosh why use a TCS and `ContinueWith` when `async/awai` is already available? `var response= Task.Factory.FromAsync(..)` will return the response and get back to the UI thread. `ConfigureAwait(false)` can be used to avoid that, eg to allow loading the image in a threadpool thread. There's no need for any of the `ContinueWith()` calls. – Panagiotis Kanavos Jan 30 '19 at 08:35
  • Also, checking if the stream is a GZip or Deflate stream is useless. Just set the [AutomaticDecompression](https://learn.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest.automaticdecompression) property of the `WebRequest` to `true` and it's all handled automatically. – Jimi Jan 30 '19 at 08:41
8

PictureBox control has built-in support for loading images asynchronously. You don't need to use BackgroundWorker or async/await. It also can load an image from a URL, so you don't need to use a web request.

You can simply use the LoadAsync method or ImageLocation property of PictureBox. The value of WaitOnLoad property should be false, which is the default.

pictureBox1.LoadAsync("https://i.stack.imgur.com/K4tAc.jpg");

It's equivalent to:

pictureBox1.ImageLocation = "https://i.stack.imgur.com/K4tAc.jpg";
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398