Потоки с изображениями WPF (System.InvalidOperationException) - PullRequest
1 голос
/ 04 мая 2011

Я использую ветку, чтобы получить изображение с веб-сайта и переместить его обратно в родительскую форму (WPF) для отображения. Я столкнулся с проблемой и смог отладить ее в следующем примере:

public void Watch()
{
  while (true)
  {
    Bitmap bmp = new Bitmap(1, 1);
    BitmapImage bmpImg = new BitmapImage();

    this.SetImage(bmp, bmpImg);
  }
}

public delegate void SetImageCallback(Bitmap bmp, BitmapImage bmpImg);

private void SetImage(Bitmap bmp, BitmapImage bmpImg)
{
  if (!this.imgVideo.Dispatcher.CheckAccess())
  {
    SetImageCallback del = new SetImageCallback(SetImage);
    this.Dispatcher.Invoke(del, bmp, bmpImg);
  }
  else
  {
    Bitmap bitmap = bmp;
    BitmapImage bitmapImage = bmpImg;
  }
}

Имейте в виду, что Watch () работает в своем собственном потоке. Если я использую растровый объект (который я могу использовать с PictureBox в Window Forms), все работает отлично. То есть отлаживая этот код, когда я попадаю в строку

Bitmap bitmap = bmp;

И проверьте переменную bmp, все отлично и работает как положено. ОДНАКО, когда я добираюсь до следующей строки

BitmapImage bitmapImage = bmpImg;

И, проверяя переменную bmpImage, я получаю массу исключений System.InvalidOperationException. Когда это происходит на практике и ему присваивается объект изображения WPF, он говорит, что «вызывающий поток не может получить доступ к этому объекту, поскольку он принадлежит другому потоку». Почему я сталкиваюсь с этой проблемой с WPF BitmapImages (которые необходимы для установки ImageSource), но НЕ в растровых объектах Windows Forms (которые можно использовать для установки PictureBox)? Как мне это исправить в WPF?

Ответы [ 2 ]

3 голосов
/ 04 мая 2011

Большинство объектов в WPF относятся к этой категории: они не могут быть разделены между разными потоками. Однако некоторые низкоуровневые ресурсы, такие как кисти и растровые изображения, получены из специального класса, называемого Freezable, который в случае замораживания может делиться между разными потоками. Конечно, если объект заморожен, он больше не может быть изменен. Чтобы заморозить замораживаемый объект, просто вызовите Freeze, и это предотвратит межпотоковые исключения.

1 голос
/ 04 мая 2011

Вместо

if (!this.imgVideo.Dispatcher.CheckAccess())
  {
    SetImageCallback del = new SetImageCallback(SetImage);
    this.Dispatcher.Invoke(del, bmp, bmpImg);
  }

попробуйте использовать:

if (!App.Current.Dispatcher.CheckAccess())
                App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action<CustomObject>(SetImage),CustomeObjectInstance );

Здесь объект Cutom будет упаковкой класса-оболочки

Bitmap bmp, BitmapImage bmpImg

Очевидно, ваша подпись SetImage будетизменить на

SetImage(CutomObject custObj)

Я не тестировал код, но это может решить проблему.Дайте нам знать, если это сработает, чтобы какая-то бедная душа могла получить пользу от этого поста.Всего наилучшего!Sid

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...