2010-12-09 3 views
8

je la méthode suivante dans une classe de base qui implémente System.ComponentModel.INotifyPropertyChanged:.NET ne peut pas effectuer cette opération pendant le traitement répartiteur est suspendu

protected virtual void RaisePropertyChangedEventSynchronous(string propertyName) 
{      
    try 
    { 
     if (PropertyChanged != null) 
     { 
      Delegate[] delegates = this.PropertyChanged.GetInvocationList(); 
      foreach (PropertyChangedEventHandler handler in delegates) 
      {      
       try 
       { 
        DispatcherObject dispatcherInvoker = handler.Target 
         as DispatcherObject; 
        if (dispatcherInvoker != null) 
        {         
         dispatcherInvoker.Dispatcher.Invoke(DispatcherPriority.Normal, 
          new Action(delegate 
         { 
          handler(this, new PropertyChangedEventArgs(propertyName)); 
         })); 
        } 
        else 
        { 
         handler(this, new PropertyChangedEventArgs(propertyName)); 
        } 
       } 
       catch (Exception ex) 
       {      
        ExceptionPolicy.HandleException(ex, 
         ExceptionHandlingPolicyNames.LogPolicy); 
       } 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     ExceptionPolicy.HandleException(ex, ExceptionHandlingPolicyNames.LogPolicy); 
    } 
} 

À l'occasion, je recevrais l'exception suivante connecté pour déposer :

type: System.InvalidOperationException, mscorlib, version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089 message: Impossible d'effectuer cette opération pendant le traitement répartiteur est suspendu. Source: WindowsBase lien Aide: données: System.Collections.ListDictionaryInternal TargetSite: Void PushFrame (System.Windows.Threading.DispatcherFrame) Stack Trace: à System.Windows.Threading.Dispatcher.PushFrame (cadre de DispatcherFrame) à System.Windows.Threading.DispatcherOperation.Wait (TimeSpan timeout) à System.Windows.Threading.Dispatcher.InvokeImpl (priorité DispatcherPriority, TimeSpan timeout, méthode Delegate, Object arguments, Boolean isSingleParameter) à System.Windows.Threading.Dispatcher. Invoke (priorité DispatcherPriority, méthode Delegate) à OCC600.Infrastructure.Dictionary.BusinessEntities.Observable.RaisePropertyChangedEventSynchronous (String propertyName)

Si j'utilise Dispatcher.BeginInvoke pour mettre à jour l'interface utilisateur, je n'obtiens pas ces exceptions. Mais j'ai découvert qu'effectuer des mises à jour en utilisant BeginInvoke n'est pas fiable car parfois ces changements ne sont pas reflétés sur l'interface utilisateur.

Comment résoudre ce problème?

Répondre

8

Je présume que vous êtes sur un thread d'arrière-plan et que vous essayez d'augmenter votre événement PropertyChanged sur le thread de l'interface utilisateur. Je pense que WPF gère le changement de thread pour vous; tu ne devrais pas avoir à faire ça.

Voici un code que j'ai écrit. XAML:

<Window x:Class="WpfApplication2.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
    <TextBlock Text="{Binding Value}" /> 
    </Grid> 

C#:

public partial class MainWindow : Window { 
    public MainWindow() { 
    InitializeComponent(); 

    this.DataContext = new Backgrounder(); 
    } 

    class Backgrounder : INotifyPropertyChanged { 
    int value = 0; 
    public Backgrounder() { 
     ThreadPool.QueueUserWorkItem(o => { 
     while (true) { 
      this.value++; 
      Notify("Value"); 
      Thread.Sleep(TimeSpan.FromSeconds(1)); 
     } 
     }); 
    } 

    public int Value { get { return this.value; } } 

    public event PropertyChangedEventHandler PropertyChanged; 

    void Notify(string property) { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) { 
     handler(this, new PropertyChangedEventArgs(property)); 
     } 
    } 
    } 
} 
+1

Merci, je vous remercie. Cela devrait simplement beaucoup de choses. Pour actualiser des collections, cependant, je dois faire un dispatcher.invoke sur la méthode CollectionView.Refresh() sinon une exception est levée. –

+0

Pour cela, vous devez utiliser Dispatcher.BeginInvoke. Il n'y a pas d'autre solution, car vous devez être sur le thread Dispatcher et il n'y a pas de moyen fiable de dire quand le Dispatcher est suspendu. –

+0

Merci. Vérifié à nouveau et j'utilise BeginInvoke pour actualiser les collections. –

Questions connexes