2010-11-30 30 views
1

Je suis assez nouveau pour travailler avec des threads. Je tentais de définir une valeur de DependencyProperty:différence entre SendOrPostCallback et Action dans un environnement multithread?

public States State 
    { 
     get { return (States)GetValue(StateProperty); } 
     set 
     { 
      Dispatcher.BeginInvoke(DispatcherPriority.Background, 
       //(SendOrPostCallback)delegate { SetValue(StateProperty, value); }, //works 
       (Action)(()=> SetValue(StateProperty, value)), //doesnt 
       value); 
     } 
    } 
    public static readonly DependencyProperty StateProperty = 
     DependencyProperty.Register("State", typeof(States), typeof(FTPDownload), new UIPropertyMetadata(States.Idle)); 

Je pris conscience de la dure que le poseur vous devez utiliser SendOrPostCallback (car il fournit un argument lors de l'appel de la méthode). il ne fonctionne PAS avec Action (à cause de l'argument manquant), et wpf est vraiment une bête à ce sujet, le débogage et la recherche de la cause de la TargetParameterCountException avec "aucune source disponible" et aucun indice du tout

Pourquoi je doivent utiliser SendOrPostCallback là et comment dois-je sais que dans ce cas, c'est la bonne raison d'appeler en fait le poseur fonctionne via:?

Dispatcher.BeginInvoke((Action)(()=>State=States.Updating), null); 

et en utilisant le SendOrPostCallback au lieu des résultats de cours dans un TargetParameterCountException ..

Je me demandais si une chose apparemment inconsistante comme celle-là ne Nowledge? Se sentir un peu perdu ici, au moins depuis googling autour avec SendOrPostCallback, Action et BeginInvoke comme mots clés n'avaient pas de résultats significatifs.

+1

Pour votre information, le poseur d'Etat est _pas called_ si la mise à jour se produit à la suite des données système de reliure. Il appellera SetValue directement. En tant que tel, cette approche de la synchronisation peut ne pas fonctionner comme prévu.La meilleure pratique générale consiste à s'assurer que toutes les mises à jour de DP se produisent sur le thread d'interface utilisateur, ce qui signifie isoler votre logique d'interface utilisateur (ViewModel) de tout travail multithread dans les données et la logique sous-jacentes (Model). –

Répondre

6

Les morceaux d'information pertinentes:

1. La surcharge de Dispatcher.BeginInvoke que vous utilisez est:

public DispatcherOperation BeginInvoke(
    DispatcherPriority priority, 
    Delegate method, 
    Object arg 
) 

method: Un délégué à un procédé qui prend un argument, qui est poussé dans la file d'attente des événements Dispatcher.

2.Les délégué SendOrPostCallBack est déclaré:

public delegate void SendOrPostCallback(object state) 

3.As pour Action:

public delegate void Action() 

De toute évidence, le délégué SendOrPostCallBack est compatible car il faut un seul argument, mais Action n'est pas , puisque c'est sans paramètre.

Bien sûr, vous pouvez utiliser le délégué Action<T>, qui -t prendre un seul argument, si vous préférez:

Dispatcher.BeginInvoke(DispatcherPriority.Background, 
         new Action<States>(arg => SetValue(StateProperty, arg)), 
         value); 

Vous pouvez également utiliser un different overload de Dispatcher.BeginInvoke qui attend un argument qui est de un type délégué qui prend pas arguments, et obtenir le compilateur C# pour faire le sale boulot dans la fermeture pour vous:

Dispatcher.BeginInvoke(DispatcherPriority.Background, 
         new Action(() => SetValue(StateProperty, value)); 

Notez que value est une variable capturée, alors soyez prudent.

(De plus, cette réponse ne traite pas des questions de sécurité des threads, seulement les signatures des délégués participant.)

+0

l'enfer, je suis stupide. bien sûr, l'une méthode prend un argument alors que l'autre ne le fait pas. bien, merci. si seulement je n'ai pas lu mettre la sécurité du fil dans les méthodes de dépendance est une mauvaise pratique il y a une minute ..;) * soupir * – kris