2010-05-12 5 views
1

Je souhaite créer un programme qui calcule le temps nécessaire pour répéter un processus un certain nombre de fois. J'ai beaucoup réduit cela pour cet exemple.Bloc de texte à plusieurs blocs WPF non mis à jour

Donc, j'ai quelques zones de texte qui sont liés à des propriétés dans une classe:

Count: <TextBox x:Name="txtCount" Text="{Binding Count, Mode=TwoWay}" Width="50"/> 
Days: <TextBox x:Name="txtDays" Text="{Binding Days, Mode=TwoWay}" Width="50"/> 

et un TextBlock qui est multibound comme ceci:

<TextBlock x:Name="tbkTotal"> 
    <TextBlock.Text> 
     <MultiBinding StringFormat="Days: {0}, Count: {1}"> 
      <Binding Path="Days" /> /* This isn't updating */ 
      <Binding Path="Count" /> 
     </MultiBinding> 
    </TextBlock.Text> 
</TextBlock> 

Mon DataContext est situé dans le Window1. Fichier xaml.cs.

public Window1() 
     { 
      InitializeComponent(); 
      Sample sample = new Sample(); 
      this.DataContext = sample; 
     } 

je peux mettre à jour le textblock multibound avec la propriété Count très bien, mais la propriété Days montre toujours 0, même si l'entrée Days reflète fidèlement les changements. Je crois que c'est parce que mes accesseurs sont différents pour Days - à savoir, la méthode Set. Cette classe est dans un fichier différent.

public class Sample : INotifyPropertyChanged 
    { 
     private int _count; 
     private TimeSpan _span; 

     public int Count 
     { 
      get { return _count; } 
      set 
      { 
       _count = value; 
       NotifyPropertyChanged("Count"); /* Doesn't seem to be needed, actually */ 
      } 
     } 

     public TimeSpan Span { get { return _span; } } 

/* The idea is to provide a property for Days, Hours, Minutes, etc. as conveniences to the inputter */ 

     public double Days 
     { 
      get { return _span.Days; } 
      set 
      { 
       TimeSpan ts = new TimeSpan(); 
       double val = value > 0 ? value : 0; 
       ts = TimeSpan.FromDays(val); 
       _span.Add(ts); /* !! This turned out to be the problem, lol - see SixLetterVariables' answer below. */ 
       NotifyPropertyChanged("Span"); /* Here I can only get it to work if I notify that Span has changed - doesn't seem to be aware that the value behind Days has changed. */ 
      } 
     } 

     private void NotifyPropertyChanged(string property) 
     { 
      if (null != this.PropertyChanged) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(property)); 
      } 
     } 
     public Sample() 
     { 
      _count = 0; 
      _span = new TimeSpan(); 
     } 
     public event PropertyChangedEventHandler PropertyChanged; 
    } 
+2

Dans votre NotifyPropertyChanged, si vous vérifiez la valeur NULL d'abord, vous devriez vraiment première copie this.PropertyChanged à une PropertyChangedEventHandler fonction locale puis vérifiez que - votre méthode laisse une chance (très petite, mais existante) d'une condition de course où le gestionnaire est retiré entre la vérification de null et l'augmentation de l'événement. – JustABill

Répondre

1

Tout d'abord TimeSpan est une struct immuable, vous aurez donc besoin de stocker le résultat de toute opération sinon il est effectivement un no-op. En outre, vous aurez besoin d'appeler OnPropertyChanged pour les Span et Days être changé:

public double Days 
{ 
    get { return _span.Days; } 
    set 
    { 
     double val = value > 0 ? value : 0; 

     // TimeSpan is an immutable struct, must store the result of any 
     // operations on it 
     _span = TimeSpan.FromDays(val); 

     this.OnPropertyChanged("Days"); 
     this.OnPropertyChanged("Span"); 
    } 
} 

// This is preferred way for handling property changes 
private event PropertyChangedEventHandler propertyChanged; 
public event PropertyChangedEventHandler PropertyChanged 
{ 
    add { this.propertyChanged += value; } 
    remove { this.propertyChanged -= value; } 
} 

protected virtual void OnPropertyChanged(string propertyName) 
{ 
    PropertyChangedEventHandler handler = this.propertyChanged; 
    if (null != handler) 
    { 
     handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 
+0

Je pensais cela aussi, mais cela ne fait aucune différence. –

+0

Correction du code, vous devez enregistrer '_span'. 'TimeSpan.Add' ne modifie pas le' TimeSpan' mais en retourne un nouveau. – user7116

+0

Vous l'avez cloué. Quelle noix je suis. Merci beaucoup :) –

Questions connexes