2009-04-27 6 views
1

J'essaie de comprendre ce qu'il est sur le code suivant qui est parfaitement heureux avec le chargement d'un fichier texte et d'afficher son contenu, mais n'est pas content de charger un BitmapImage et de l'afficher sur un gestionnaire d'événement timer.Elapsed. Je comprends que cela a à voir avec le thread de l'interface utilisateur.WPF événement: BitmapImage PropertyChanged: « L'appel de cette discussion ne peut pas accéder »

Mais pourquoi cela ne pose-t-il pas un problème pour l'exemple textfile?

D'abord, le 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> 

et C#, ce qui soulève un PropertyChangedEventHandler sur une minuterie:

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

et

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

Je sais que je peux résoudre ce problème avec un "Application.Current.Dispatcher.Invoke". Donc, la réparation n'est pas le problème. Ne pas comprendre pourquoi je dois est le problème :)

similaires aux questions

Répondre

2

Je pense que la différence essentielle entre les deux scénarios est que BitmapImage est un objet de dépendance, ce qui signifie qu'il a le c oncept d'un thread "propriétaire" (le thread qui a créé l'objet). Lorsque votre thread UI principal tente d'accéder à l'objet BitmapImage créé sur (et détenu par) un autre thread ... boom!

Les chaînes, d'autre part, n'ont pas de concept de fil "propriétaire".

+0

Merci Daniel cela m'a vraiment aidé à comprendre la racine du problème. –

1

Je pense que c'est parce que BitmapImage est DispatchObject; vous créez un DispatcherObject sur le thread non-UI, donc l'exception. Vous ne voyez pas d'erreur avec l'affectation de texte car le texte n'est pas un objet fileté.

2

Pour ceux d'entre nous (comme moi) qui est venu ici à la recherche pour voir comment passer réellement bitmaps à travers les discussions, consultez

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

La réponse est à Freeze() le bitmap premier.

Questions connexes