2017-08-20 11 views
0

J'essaie de créer une boucle infinie CPU qui mettra à jour une étiquette toutes les 2 secondes.L'utilisation de Dispatcher pour modifier l'avant-plan d'une étiquette déclenche une exception

Quand il vient de mettre à jour l'étiquette, je peux utiliser Dispatcher changer ses valeurs Content et ToolTip, mais je ne peux pas changer son Foreground pour une raison quelconque.

InvalidOperationException: ne peut pas utiliser un DependencyObject qui appartient à un autre thread que son parent Freezable.

Il est mon code:

private void SetPing(Brush foreground, string content, string tooltip) 
{ 
    try 
    { 
     this.Dispatcher.BeginInvoke(DispatcherPriority.Send, (Action)(() => 
     { 
      this.Ping.Content = content; 
      this.Ping.ToolTip = tooltip; 
     })); 

     // this.Dispatcher or this.Ping.Dispatcher throws the same error 
     this.Ping.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => 
     { 
      this.Ping.Foreground = foreground; 
     })); 
    } 
    catch (Exception) 
    { 
    } 
} 

Je vous appelle ce code de la méthode PerformPing ici:

new Thread(() => 
{ 
    while (true) 
    { 
     this.PerformPing(this.Host); 
     Thread.Sleep(1); 
    } 
}).Start(); 

(Oui, je sais que ce n'est pas un CPU convivial boucle, j'ai fait cela à des fins de test).

+0

Sans un bon [mcve] qui reproduit de manière fiable le problème, il est impossible de dire avec certitude quel est le problème. Mais selon le petit morceau de code que vous avez partagé, je suppose que vous créez votre objet 'Brush' dans le thread d'arrière-plan. Ce n'est généralement pas autorisé. Vous pouvez le faire fonctionner en appelant 'Freeze()' sur 'Brush' après l'avoir créé. Mais franchement, il serait préférable que vous appreniez la façon correcte d'écrire un programme WPF, y compris en utilisant MVVM/liaison de données avec des styles. Alors vous n'auriez pas besoin de 'BeginInvoke()' du tout. (Et, en utilisant 'Thread.Sleep (1)' est _not_ _ "CPU-friendly" _.) –

+0

Le code entier n'ajoute pas beaucoup. La seule chose que 'PerformPing' fait est d'effectuer un ping et d'appeler' SetPing' avec le résultat, où l'objet 'Brush' est récupéré via un' BrushConverter'. Est-ce que ça aide? Je vais essayer 'Freeze()'. En outre, c'est un très petit programme que j'ai fait pour le mien. Je n'ai pas besoin de styles ni de liaison de données dans celui-ci. De plus, comme je l'ai dit '(Oui, je sais que ce n'est pas une boucle CPU-friendly, j'ai fait cela à des fins de test).' Mais merci quand même. – Hawezo

+0

_ "Je n'ai pas besoin de styles ni de liaison de données dans celui-ci" _ - c'est sûr. Ce n'est pas parce que c'est un très petit programme que vous avez fait pour vous, que cela ne veut pas dire qu'il n'y a pas de raison de le faire. –

Répondre

0

Grâce à la réponse de Peter Duniho, j'ai compris que l'objet brush a été créé dans le thread d'arrière-plan, et c'est ce qui a provoqué le problème. La création du pinceau dans l'appel Dispatcher résout le problème.

private void SetPing(long ping, string content, string tooltip) 
{ 
    try 
    { 
     this.Dispatcher.BeginInvoke(DispatcherPriority.Send, (Action)(() => 
     { 
      this.Ping.Content = content; 
      this.Ping.ToolTip = tooltip; 
      this.SetDock(); 
     })); 

     if (this.EnableColors) 
     { 
      this.Ping.Dispatcher.BeginInvoke(DispatcherPriority.Send, (Action)(() => 
      { 
       this.Ping.Foreground = this.GetColorByPing(ping); 
      })); 
     } 
    } 
    catch (Exception ex) 
    { 
    } 
} 

GetColorByPing() retours quelque chose comme return (SolidColorBrush)new BrushConverter().ConvertFromString("#b71c1c");