2017-01-28 1 views
2

J'ai une méthode que j'appelle du thread principal. Cette méthode crée un nouveau thread. Le code ressemble à ceci:"Le thread appelant ne peut pas accéder à cet objet car un thread différent le possède" lors de la mise à jour du contrôle de l'interface utilisateur depuis un thread différent dans WPF

MouseCursorWallObject MouseCursorWall = null; 
List<MovingRectangle> MovingRectangles = null; 

DrawingImage RenderedImage; 


public MainWindow() 
    { 
     InitializeComponent(); 
     PrepareObjects();    
     GameLoopRun();      
    } 

private void GameLoopRun() 
    { 
     Thread thread = new Thread(() => 
     { 
      while (true) 
      { 
       DateTime dtStart = DateTime.Now; 

       Events(); 
       Update(); 
       Display(); 

       DateTime dtEnd = DateTime.Now; 
       TimeSpan ts = dtEnd - dtStart; 
       if (SkipTicks - ts.TotalMilliseconds >= 0) 
       { 
        Thread.Sleep((int)(SkipTicks - ts.TotalMilliseconds)); 
       } 
      } 
     }); 
     thread.Start(); 
    } 

Dans la méthode Display(), j'essaie de mettre à jour le contrôle Image. « Affichage() » méthode ressemble à ceci:

private void Display() 
    { 
     DrawingGroup imageDrawings = new DrawingGroup(); 

     // Drawing main canvas 
     imageDrawings.Children.Add(DrawingObject(500, 350, 0, 0, new Uri(@"Images\gameCanvas.jpg", UriKind.Relative))); 

     // Drawing mouse cursor wall 
     imageDrawings.Children.Add(DrawingObject(MouseCursorWall.Width, MouseCursorWall.Height, MouseCursorWall.GetLocX, MouseCursorWall.GetLocY, MouseCursorWall.DisplayTexture)); 

     for (int i = 0; i < MovingRectangles.Count; i++) 
     { 
      MovingRectangle o = MovingRectangles[i]; 

      // Drawing moving object 
      imageDrawings.Children.Add(DrawingObject(20, 20, o.GetLocX, o.GetLocY, o.TextureUri)); 
     } 

     if (GamePause == true) 
     { 

     } 
     RenderedImage = new DrawingImage(imageDrawings); 

     // Image control on main UI thread 
     renderImage.Dispatcher.Invoke(() => 
     { 
      renderImage.Source = RenderedImage; 
     }); 
    } 

Le problème est quand I'am essayer la mise à jour le contrôle de l'image en utilisant Dispatcher.Invoke I'am erreur de réception « Le thread appelant ne peut pas accéder à cet objet parce qu'un autre thread est propriétaire il". J'ai essayé beaucoup d'options différentes, et une seule fonctionne très bien:

private void Display() 
    { 
     this.Dispatcher.Invoke(() => { 
      DrawingGroup imageDrawings = new DrawingGroup(); 

      // Drawing main canvas 
      imageDrawings.Children.Add(DrawingObject(500, 350, 0, 0, new Uri(@"Images\gameCanvas.jpg", UriKind.Relative))); 

      // Drawing mouse cursor wall 
      imageDrawings.Children.Add(DrawingObject(MouseCursorWall.Width, MouseCursorWall.Height, MouseCursorWall.GetLocX, MouseCursorWall.GetLocY, MouseCursorWall.DisplayTexture)); 

      for (int i = 0; i < MovingRectangles.Count; i++) 
      { 
       MovingRectangle o = MovingRectangles[i]; 

       // Drawing moving object 
       imageDrawings.Children.Add(DrawingObject(20, 20, o.GetLocX, o.GetLocY, o.TextureUri)); 
      } 

      if (GamePause == true) 
      { 

      } 

      RenderedImage = new DrawingImage(imageDrawings); 
      renderImage.Source = RenderedImage; 
     }); 

    } 

Pouvez-vous me expliquer pourquoi deuxième option de la méthode « Affichage() » fonctionne très bien, mais le premier lancer exception? Qu'est ce que je fais mal?

+0

J'ai déjà trouvé ce sujet. – Shagohad

+0

Ok, bien, vous pourriez être en mesure de faire fonctionner le premier exemple si vous .Freeze() le DrawingImage d'abord, mais vous devriez probablement le créer sur le thread UI (selon votre deuxième exemple). – Dutts

Répondre

3

Les deux DrawingImage et DrawingGroup héritent de DispatcherObject, ce qui signifie qu'ils doivent être accessibles à partir du thread sur lequel ils ont été créés. C'est pourquoi votre version où tout le travail est invoqué vers le répartiteur fonctionne correctement.

Comme l'a souligné Brian Reichle, ces objets héritent également de System.Windows.Freezable, que vous pouvez utiliser pour autoriser l'accès croisé aux objets.

+0

Merci pour votre réponse! Je vais vérifier ça maintenant. – Shagohad

+1

"... héritent de DispatcherObject, ce qui signifie qu'ils doivent être accessibles à partir du thread sur lequel ils ont été créés." ... à moins qu'ils ne soient gelés. –