WPF Event: BitmapImage PropertyChanged: "Calling Thread Cannot access"

WPF Event: BitmapImage PropertyChanged: "Calling Thread Cannot access"

心欲静而疯不止 发布于 2021-11-28 字数 3433 浏览 785 回复 3 原文

I'm trying to understand what it is about the following code that is perfectly happy with loading a text file and displaying its contents, but isn't happy with loading a BitmapImage and displaying it on a timer.Elapsed event handler.

I understand it has to do with the UI thread.

But why is this not a problem for the textfile example?

First, the XAML:

<Window x:Class="WpfApplication7.Window1"
    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"/>


and the C#, which raises a PropertyChangedEventHandler on a timer:

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()
      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:windowswin.ini").Substring(0, 20);
        PropertyChanged(this, new PropertyChangedEventArgs("Message"));

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

          this.Image = new BitmapImage(new Uri(@"C:WINDOWSWebWallpaperAscent.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"));

I know I can fix this with a "Application.Current.Dispatcher.Invoke". So fixing it isn't the problem. Not understanding why I should have to is the problem :)

Similar questions

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。



需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。


£噩梦荏苒 2022-06-07 3 楼

I think it's because BitmapImage are DispatchObject's; you are creating a DispatcherObject on the non-UI thread thus the exception. You don't see error with the text assignment since the text isn't a threaded object.

为你鎻心 2022-06-07 2 楼

For those of us (like me) who came here looking to see how to actually pass bitmaps across threads, check out


The answer is to Freeze() the bitmap first.

盛夏尉蓝 2022-06-07 1 楼

I think the critical difference between the two scenarios is that BitmapImage is a dependency object, which means it has the concept of an "owning" thread (the thread that created the object). When your main UI thread tries to access the BitmapImage object created on (and owned by) another thread...boom!

Strings, on the other hand, do not have a concept of an "owning" thread.