1

Here is some sample code to better illustrate what I am trying to accomplish here. Basically I need to set property which can only be set from UI thread. Any ideas?

public ref class ExtendedImage : public System::Windows::Controls::Image
    {
public:
    void SetImageFromUrl (System::String^ url)
        {
         if (!System::Uri::TryCreate (path, System::UriKind::Absolute, this->m_uri) || this->m_uri->IsFile)
            return;

        System::Threading::Thread^ downloadImage = gcnew System::Threading::Thread (gcnew System::Threading::ThreadStart (this, &ExtendedImage::DownloadAndSetImage));
        downloadImage->Start ();
        }

private:
    System::Uri^ m_uri;

    void DownloadAndSetImage ()
        {
        System::Windows::Media::Imaging::BitmapImage^ bitmap = gcnew System::Windows::Media::Imaging::BitmapImage (this->m_uri);

        //execute this->Source = bitmap; on UI thread
        }
    }

Update: A bit of useful information after combining question code to correct answer C# solution. To get UI thread Dispatcher use System::Windows::Application::Current->Dispatcher.

Harazi
  • 122
  • 1
  • 10

1 Answers1

3

Creating a BitmapImage from an URI is already performed asynchronously by WPF, so there is no need to start another thread.

Just do it this way:

using namespace System;
using namespace System::Windows::Controls;
using namespace System::Windows::Media::Imaging;

public ref class ExtendedImage : public Image
{
public:
    void SetImageFromUrl(System::String^ url)
    {
        Uri^ uri;

        if (Uri::TryCreate(url, UriKind::Absolute, uri) && !uri->IsFile)
        {
            Source = gcnew BitmapImage(uri);
        }
    }
};

Anyway, if you really need to manually download an image buffer from an URI and create a BitmapImage from that buffer in a separate thread, you may follow the approach shown in this answer to a similar question.

Community
  • 1
  • 1
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Your answer led me to do some more research on this, since UI freezes if I just do it the way you suggest (basically it was the first thing I tried when I run into freezing UI problem and decided to use threads, but, of course, I tried it again after your answer, just to make sure.) It looks like it is not done automatically by WPF, unless dependency property binding option `IsAsync` is set to true. Which is pretty important to notice I believe. Either-way, in my case I can't use XAML, so it has to be done in code. – Harazi Aug 07 '14 at 11:02
  • So in order to mess with bindings, I have to override OnApplyTemplate, however, strangely it is not being called (but that's another issue). Also as for setting image Source property, I only want it to be asynchronous when uri path is URL. So, could you update your answer, if you know how I could achieve this? I have already figured out how to make it work with threads, but your answer, if you will update it to make it clear - would be more appropriate I believe. – Harazi Aug 07 '14 at 11:09
  • No idea about which bindings you're talking here. Your question just has a `SetImageFromUrl` method. Unless the URL does not refer to a local file, WPF will load the image asynchronously. – Clemens Aug 07 '14 at 11:21
  • Here is a similar issue in C# http://stackoverflow.com/questions/16035300/make-wpf-image-load-async , answer with the highest score tells how to do it with XAML, however as I mentioned, I can not use XAML in my case. And URL does not refer to local file. In fact `!uri->IsFile` takes care of it, as it will fail if it is a local file. And as much as I wish it to be true, it's not done automatically, unresponsive UI proves it. – Harazi Aug 07 '14 at 11:45
  • Then you might just follow the suggestion given in [my answer](http://stackoverflow.com/a/16041810/1136211) to the same question. Please also take a close look at the comments on the highly upvoted answer, regarding the fact that the binding converter is *not called* asynchronously, even if the binding's `IsAsync` property is set to true. Even though the answer has most votes, it does *not solve* the problems that was asked for in the question. – Clemens Aug 07 '14 at 11:48
  • Well this would be done in separate thread in that case, just like originally I intended to. (but your current answer encouraged me to search for more appropriate solution) It sure answers to this question. You should update your answer with the link to your C# solution, so I could accept it for correct one :). And thank you for time and patience with me. – Harazi Aug 07 '14 at 11:56