2009-12-15 6 views
1

Dans mon application .NET construite avec WPF et C#, j'appelle une fonction asynchrone en utilisant AsyncMethodCaller. Dans le rappel, je voudrais mettre à jour certaines données dans l'interface graphique, mais je ne suis pas autorisé à le faire car cela est la propriété du thread principal. Comment je le fais?Fonction asynchrone - rappel utilisant un objet appartenant au thread principal

  • Vous appelez une mise à jour sur le thread principal? Comment?
  • Passez un objet (par exemple ViewModel) en tant qu'état au rappel et mettez à jour les données à ce sujet - qui est lié à nouveau à l'interface graphique?
  • D'une autre façon?

Quel est le moyen commun, recommandé de gérer cela?

L'erreur d'exécution est donné:

Le thread appelant ne peut pas accéder à cet objet parce qu'un autre thread est propriétaire.

Répondre

3

Vous devez appeler la méthode à l'aide de Dispatcher, en appelant la méthode Dispatcher.Invoke. Cette MSDN article explique comment mettre à jour l'interface utilisateur dans WPF à partir d'opérations asynchrones en détail.

0

J'ai essayé de transmettre l'objet ViewModel asyncState de sorte que le rappel puisse accéder à cet objet. Le rappel met généralement à jour certaines propriétés avec une valeur reçue de l'appel de fonction asynchrone. Le ViewModel finira par être où je veux faire la mise à jour de l'état de toute façon. Est-ce une bonne façon de le gérer? Ou devrais-je toujours utiliser Dispatcher.Invoke?

Le ViewModel:

public class MyViewModel : BaseViewModel 
{ 
    public int Result 
    { 
     get { return _result; } 
     set 
     { 
      _result = value; 
      this.RaisePropertyChanged("Result"); 
     } 
    } 
} 

Appel de la fonction:

caller.BeginInvoke(num1, num2, new AsyncCallback(CallbackMethod), _myViewModel); 

Le rappel met à jour le viewmodel:

private void CallbackMethod(IAsyncResult ar) 
{ 
    var result = (AsyncResult)ar; 
    var caller = (AsyncMethodCaller)result.AsyncDelegate; 
    var vm = ar.AsyncState as MyViewModel; 
    int returnValue = caller.EndInvoke(ar); 
    vm.Result = returnValue; 
} 
2

Bambuska,

En utilisant Dispatcher est vraiment beaucoup ea sier que vous ne le pensez. S'il vous plaît jeter un oeil à mon code:

public class MyViewModel : BaseViewModel  
{  
    public int Result  
    {  
     get { return _result; }  
     set  
     {  
      _result = value;  

      Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new WorkMethod(delegate 
       { 
        this._result = SampleMethodChangingResult(); 
       })); 

      this.RaisePropertyChanged("Result");  
     }  
    }  
} 

Cela devrait fonctionner (il fait dans mon cas). En tout cas, merci de me tenir au courant.

+0

Merci! Le principe que vous montrez ici m'aide, même si le code ne semble pas fonctionner «hors de la boîte». Et feriez-vous vraiment l'invocation du viewmodel? Cela voudrait dire que vous devez passer l'objet viewModel comme état de toute façon que vous ne pouvez pas accéder à ce soit si appartenant au thread principal? Donc je suppose que vous feriez l'appel directement à partir du rappel? – stiank81

+0

Voici ce que je fais du rappel. Notez que je ne peux pas utiliser Dispatcher.CurrentDispatcher.Invoke car j'ai besoin de celui appartenant au thread principal - je suppose ..? Application.Current.Dispatcher.Invoke (DispatcherPriority.Normal, (ThreadStart) (() => UpdateSomething (returnValue))); – stiank81

+0

Je suppose que vous pouvez faire cela, mais pourquoi insistez-vous pour passer l'objet vm? Vous pouvez certainement exécuter mon code dans l'objet vm et puisque vm est lié à un objet de vue en tant que DataContext, il est certainement exécuté dans le thread principal. –

Questions connexes