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"
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>
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;
and
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"));
//}));
};
}
}
}
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