0

I have created a thread, but the thread pauses the main process after I start it. The thread loads some images from google, but when the internet connection is lost the user interface is unusable.

This is the thread:

string searchWord = "car photo";
PhotoSearchThread = new Thread(() =>
{
    Thread.CurrentThread.IsBackground = true;
    if (!string.IsNullOrWhiteSpace(searchWord))
    {
        string html = GetHtmlCode(searchWord);
        SearchedImagesUrls = GetUrls(html); 
        this.Dispatcher.Invoke(() =>
        {
            if (SearchedImagesUrls.Count > 0)
            {
                BitmapImage image = new BitmapImage();
                image.BeginInit();
                image.CacheOption = BitmapCacheOption.OnLoad;
                image.UriSource = new Uri(SearchedImagesUrls[0]);
                image.EndInit();
                SelectPhotoImage.Source = image; 
            }
        });
    }
});

PhotoSearchThread.Start();

Well threads should run simultaneously, then why this thread is interrupting other threads?

JNYRanger
  • 6,829
  • 12
  • 53
  • 81
  • 2
    You do realize that the `Invoke` is telling it to run that code on your main thread. I'm guessing that `SelectPhotoImage.Source = image;` is the only part that needs to be in the `Invoke`. – juharr Jul 05 '17 at 21:01
  • Aha, I didn't know that. Thanks for your answer. But is there anyway to seperate them and at the same time change the image source? – Benjamin Ronneling Jul 05 '17 at 21:05
  • 1
    Just put everything but the assignment outside the invocation? – Jeroen Vannevel Jul 05 '17 at 21:06
  • Thanks for your answer Jeroen. I am afraid that the image loading function takes longer than it should and the image assignment won't work because the link array not yet ready... – Benjamin Ronneling Jul 05 '17 at 21:09

2 Answers2

3

Invoke is used to run code on the main or UI thread. Specifically for updating UI elements as those can only be updated by that thread. Currently you have code that loads the image in the Invoke. Instead you should only put the part of the code that updates the UI inside of the Invoke.

PhotoSearchThread = new Thread(() =>
{
    Thread.CurrentThread.IsBackground = true;
    if (!string.IsNullOrWhiteSpace(searchWord))
    {
        string html = GetHtmlCode(searchWord);
        SearchedImagesUrls = GetUrls(html); 

        if (SearchedImagesUrls.Count > 0)
        {
            BitmapImage image = new BitmapImage();
            image.BeginInit();
            image.CacheOption = BitmapCacheOption.OnLoad;
            image.UriSource = new Uri(SearchedImagesUrls[0]);
            image.EndInit();
            this.Dispatcher.Invoke(() =>
            {
                SelectPhotoImage.Source = image; 
            });
        }
    }
});
juharr
  • 31,741
  • 4
  • 58
  • 93
0

I found the solution:

1.Add following using: using System.ComponentModel;

2.Declare background worker:

private readonly BackgroundWorker worker = new BackgroundWorker();

3.Subscribe to events:

worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;

4.Implement two methods:

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
   // run all background tasks here
}

private void worker_RunWorkerCompleted(object sender, 
                                       RunWorkerCompletedEventArgs e)
{
  //update ui once worker complete his work
}

5.Run worker async whenever your need.

worker.RunWorkerAsync();

Also if you want to report process progress you should subscribe to ProgressChanged event and use ReportProgress(Int32) in DoWork method to raise an event. Also set following: worker.WorkerReportsProgress = true; (thanks to @zagy)

source: How to use WPF Background Worker

Hope this help.