C++/cli wpf устанавливает свойство в потоке пользовательского интерфейса из другого потока

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

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
        }
    }

Обновление: немного полезной информации после объединения кода вопроса для правильного ответа на решение C#. Чтобы получить диспетчер потока пользовательского интерфейса, используйте System::Windows::Application::Current->Dispatcher.


person Harazi    schedule 06.08.2014    source источник


Ответы (1)


Создание BitmapImage из URI уже выполняется WPF асинхронно, поэтому нет необходимости запускать еще один поток.

Просто сделайте это так:

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);
        }
    }
};

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

person Clemens    schedule 06.08.2014
comment
Ваш ответ побудил меня провести дополнительное исследование по этому вопросу, поскольку пользовательский интерфейс зависает, если я просто делаю это так, как вы предлагаете (в основном это было первое, что я попробовал, когда столкнулся с проблемой зависания пользовательского интерфейса и решил использовать потоки, но, конечно , я попробовал еще раз после вашего ответа, просто чтобы убедиться.) Похоже, WPF не делает это автоматически, если для параметра привязки свойства зависимостей IsAsync не установлено значение true. Что довольно важно заметить, я считаю. В любом случае, в моем случае я не могу использовать XAML, поэтому это нужно делать в коде. - person Harazi; 07.08.2014
comment
Итак, чтобы возиться с привязками, я должен переопределить OnApplyTemplate, однако, как ни странно, он не вызывается (но это другая проблема). Кроме того, что касается установки свойства источника изображения, я хочу, чтобы оно было асинхронным только тогда, когда путь uri является URL-адресом. Итак, не могли бы вы обновить свой ответ, если знаете, как я могу этого добиться? Я уже понял, как заставить его работать с потоками, но ваш ответ, если вы обновите его, чтобы было понятно, будет более подходящим, я считаю. - person Harazi; 07.08.2014
comment
Понятия не имею, о каких привязках вы здесь говорите. В вашем вопросе есть только метод SetImageFromUrl. Если URL-адрес не указывает на локальный файл, WPF будет загружать изображение асинхронно. - person Clemens; 07.08.2014
comment
Вот аналогичная проблема в С# stackoverflow.com/questions/ 16035300/make-wpf-image-load-async , ответ с наивысшим баллом говорит, как это сделать с помощью XAML, однако, как я уже упоминал, в моем случае я не могу использовать XAML. И URL не относится к локальному файлу. На самом деле !uri->IsFile позаботится об этом, так как если это локальный файл, это не удастся. И как бы я ни хотел, чтобы это было правдой, это не делается автоматически, это доказывает невосприимчивый пользовательский интерфейс. - person Harazi; 07.08.2014
comment
Тогда вы можете просто следовать предложению, данному в мой ответ на тот же вопрос. Также внимательно ознакомьтесь с комментариями к ответу, получившему большое количество голосов, относительно того факта, что преобразователь привязки не вызывается асинхронно, даже если для свойства IsAsync привязки установлено значение true. Несмотря на то, что ответ получил наибольшее количество голосов, он не решает проблемы, о которых говорилось в вопросе. - person Clemens; 07.08.2014
comment
Что ж, в этом случае это будет сделано в отдельном потоке, как я и планировал изначально. (но ваш текущий ответ побудил меня искать более подходящее решение) Он точно отвечает на этот вопрос. Вы должны обновить свой ответ ссылкой на свое решение С#, чтобы я мог принять его за правильное :). И спасибо за время и терпение со мной. - person Harazi; 07.08.2014