Событие WPF: BitmapImage PropertyChanged: «Вызывающий поток не может получить доступ» - PullRequest
1 голос
/ 27 апреля 2009

Я пытаюсь понять, что из следующего кода: совершенно доволен загрузкой текстового файла и отображением его содержимого, но не доволен загрузкой BitmapImage и отображение его в обработчике события timer.Elapsed.

Я понимаю, что это связано с потоком пользовательского интерфейса.

Но почему это не проблема для примера с текстовым файлом?

Во-первых, XAML:

<Window x:Class="WpfApplication7.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

<StackPanel Orientation="Vertical">

<TextBlock Text="{Binding Path=Message, UpdateSourceTrigger=PropertyChanged}" FontSize="20" Height="40" Width="300"  Background="AliceBlue"  />

<Image Source="{Binding Path=Image,UpdateSourceTrigger=PropertyChanged}" Height="100" Width="100"/>

</StackPanel>
</Window>

и C #, который вызывает PropertyChangedEventHandler по таймеру:

using System;
using System.ComponentModel;
using System.Timers;
using System.Windows;
using System.IO;
using System.Windows.Threading;
using System.Windows.Media.Imaging;

и

namespace WpfApplication7
{
  public partial class Window1 : Window, INotifyPropertyChanged
  {
    public BitmapImage Image { get; private set; }
    public string Message { get; set; }
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    private Timer timer;

    public Window1()
    {
      InitializeComponent();
      this.DataContext = this;

      this.timer = new Timer { Enabled = true, Interval = 100 };

      this.timer.Elapsed += (s, e) =>
      {
        //---happy loading from text file. UI updates :)
        this.Message = File.ReadAllText(@"c:\windows\win.ini").Substring(0, 20);
        PropertyChanged(this, new PropertyChangedEventArgs("Message"));

        //---not happy loading a BitmapImage. PropertyChanged unhappy :(
        // (Don't make me have to: ! )
        //Application.Current.Dispatcher.Invoke(
        //DispatcherPriority.Send, new Action(delegate
        //{

          this.Image = new BitmapImage(new Uri(@"C:\WINDOWS\Web\Wallpaper\Ascent.jpg"));

          //Edit --Ah hah, thanks Daniel ! 
          // DependencyObject-> Freezable-> Animatable-> 
          // ImageSource-> BitmapSource-> BitmapImage
          this.Image.Freeze();  //<--- this will fix it, no need for Dispatcher

          //Without Dispatcher or Freeze() ... right here:
          //"The calling thread cannot access this object because a different thread owns it."
          PropertyChanged(this, new PropertyChangedEventArgs("Image"));
        //}));
      };
    }
  }
}

Я знаю, что могу исправить это с помощью «Application.Current.Dispatcher.Invoke». Так что исправить это не проблема. Непонимание, почему я должен это проблема:)

Подобные вопросы

Ответы [ 3 ]

2 голосов
/ 02 февраля 2012

Для тех из нас (как я), которые пришли сюда, чтобы посмотреть, как на самом деле передавать растровые изображения по потокам, посмотрите

https://stackoverflow.com/a/2672929/745913

Ответ на Freeze() сначала растровое изображение.

2 голосов
/ 27 апреля 2009

Я думаю, что критическое различие между этими двумя сценариями состоит в том, что BitmapImage является объектом зависимости, что означает, что он имеет понятие «владеющего» потока (потока, создавшего объект). Когда ваш основной поток пользовательского интерфейса пытается получить доступ к объекту BitmapImage, созданному (и принадлежащему) другому потоку ... boom!

С другой стороны, у строк нет понятия «владеющий» поток.

1 голос
/ 28 апреля 2009

Я думаю, это потому, что BitmapImage являются объектами DispatchObject; вы создаете объект DispatcherObject в потоке, не являющемся пользовательским интерфейсом, таким образом, исключение. Вы не видите ошибку при назначении текста, так как текст не является многопоточным объектом.

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