2009-04-27 2 views
1

Ich versuche zu verstehen, was es zu folgendem Code ist, dass ist vollkommen glücklich mit einer Textdatei laden und dessen Inhalt angezeigt wird, aber ist nicht zufrieden mit dem Laden eines BitmapImage und dessen Anzeige auf einem Timer.Elapsed-Ereignishandler.WPF Ereignis: Bitmapproperty: „Calling Thread kann nicht zugreifen“

Ich verstehe, dass es mit dem UI-Thread zu tun hat.

Aber warum ist das kein Problem für das Textdateibeispiel?

Erstens, die 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> 

und die C#, das eine PropertyChangedEventHandler auf einem Timer erhöht:

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

und

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

Ich weiß, ich kann dieses Problem beheben mit ein "Application.Current.Dispatcher.Invoke". Also ist es nicht das Problem, es zu reparieren. Nicht zu verstehen, warum muß ich soll das Problem ist :)

ähnliche Fragen

Antwort

2

Ich denke, den entscheidenden Unterschied zwischen den beiden Szenarien ist, dass BitmapImage ein Abhängigkeitsobjekt ist, was bedeutet, dass es das c einmal von einem "besitzenden" Thread (der Thread, der das Objekt erstellt hat). Wenn dein Haupt-UI-Thread versucht, auf das BitmapImage-Objekt zuzugreifen, das auf einem anderen Thread erstellt wurde (und ihm gehört) ... boom!

Strings, auf der anderen Seite, haben kein Konzept eines "besitzenden" Threads.

+0

Daniel danke das hat mir wirklich geholfen, die Wurzel des Problems zu verstehen. –

1

Ich denke, es ist, weil BitmapImage DispatchObject sind; Sie erstellen ein DispatcherObject im Nicht-UI-Thread, also die Ausnahme. Bei der Textzuweisung wird kein Fehler angezeigt, da es sich bei dem Text nicht um ein Thread-Objekt handelt.

Verwandte Themen