2009-04-07 3 views
2

Avec le code ci-dessous, j'obtiens le message Firing C Binding et le message Firing F Binding. Pourquoi donc? Je m'attends à recevoir uniquement le message Firing C Binding.Pourquoi un feu de liaison, même si la propriété liée ne change pas?

class Program : Form 
{ 
    private Label lblC; 
    private Label lblF; 
    private Button btnCUp; 
    private Temp t; 

    public Program() 
    { 
     lblC = new Label(); 
     lblF = new Label(); 
     btnCUp = new Button(); 
     t = new Temp(); 

     lblC.Location = new Point(22, 21); 
     lblC.Size = new Size(35, 13); 
     Binding b = new Binding("Text", t, "C"); 
     b.Format += new ConvertEventHandler(CLabelFormat); 
     lblC.DataBindings.Add(b); 

     lblF.Location = new Point(108, 21); 
     lblF.Size = new Size(35, 13); 
     Binding b2 = new Binding("Text", t, "F"); 
     b2.Format += new ConvertEventHandler(FLabelFormat); 
     lblF.DataBindings.Add(b2); 

     btnCUp.Location = new Point(45, 55); 
     btnCUp.Text = "C Up"; 
     btnCUp.Click += new EventHandler(btnCUp_Click); 

     this.ClientSize = new Size(165, 113); 
     this.Controls.Add(lblC); 
     this.Controls.Add(lblF); 
     this.Controls.Add(btnCUp); 
    } 

    private void CLabelFormat(object sender, ConvertEventArgs cevent) 
    { 
     MessageBox.Show("Firing C Binding"); 
    } 

    private void FLabelFormat(object sender, ConvertEventArgs cevent) 
    { 
     MessageBox.Show("Firing F Binding"); 
    } 

    [STAThread] 
    public static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 
     Application.Run(new Program()); 
    } 

    private void btnCUp_Click(object sender, EventArgs e) 
    { 
     t.incC(); 
    } 
} 

class Temp : INotifyPropertyChanged 
{ 
    private double tempC; 
    private double tempF; 

    public event PropertyChangedEventHandler PropertyChanged; 

    public Temp() 
    { 
     tempC = 0; 
     tempF = ctof(tempC); 
    } 

    private void NotifyPropertyChanged(String field) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(field)); 
     } 
    } 

    private double ctof(double c) 
    { 
     return c * 9.0/5.0 + 32; 
    } 

    public void incC() 
    { 
     ++tempC; 
     tempF = ctof(tempC); 
     NotifyPropertyChanged("C"); 
     //NotifyPropertyChanged("F"); 
    } 

    public double C 
    { 
     get { return tempC; } 
    } 

    public double F 
    { 
     get { return tempF; } 
    } 
} 

Si je retire le commentaire devant NotifyPropertyChanged("F"), puis-je obtenir quatre boîtes de message lorsque j'appuie sur le bouton. Deux pour "Firing C Binding" et deux pour "Firing F Binding".

Comment puis-je modifier le code pour n'en obtenir qu'un seul de chaque?


EDIT: J'ai essayé de regarder la source pour la liaison (avec réflecteur) pour voir ce qu'il fait quand un événement PropertyChanged est tiré, mais couln't trouver quoi que ce soit. Quelqu'un peut-il donner un aperçu? Je veux confirmer qu'il se soucie de ce que le champ est changé.

EDIT: J'ai remplacé mon code par un exemple d'implémentation compilable qui illustre le problème.

Répondre

0

Je suppose que lorsqu'une propriété change, cela indique qu'elle peut avoir eu un effet sur une autre propriété, entraînant ainsi la mise à jour de cette propriété. Très souvent, les événements de modification de propriété déclenchent un objet même s'il n'a pas été modifié, car le développeur ne souhaite pas vérifier la présence d'un changement. Il déclenche donc simplement l'événement dans les scénarios où il a pu être modifié. Mon instinct suggère que cela pourrait être ce que vous vivez.

Cependant, il se peut aussi que, quelle que soit l'écoute, l'événement PropertyChanged ne vérifie pas réellement le nom de la propriété qui a été modifiée. Cela causerait aussi le même problème.

+0

"Je suppose que lorsqu'une propriété change, cela indique qu'elle peut avoir eu un effet sur une autre propriété". Où est-ce que cela "indiquerait" cela? J'ai ajouté l'implémentation de NotifyPropertyChanged à mon message d'origine pour montrer ce qui se passe là-bas. – Tobbe

+0

A propos de l'événement PropertyChanged: N'est-ce pas la classe Binding qui l'écoute? J'espère que MS n'a pas seulement décidé d'ignorer le nom de la propriété quand ils ont implémenté cette classe :) – Tobbe

+0

Je l'espère aussi, mais des choses plus étranges sont arrivées. –

2

L'événement PropertyChanged tire qu'une seule fois, que vous pouvez vous tester:

t.PropertyChanged += t_PropertyChanged; 

void t_PropertyChanged(object sender, PropertyChangedEventArgs e) { 
    MessageBox.Show("Property Changed: " + e.PropertyName); 
} 

L'événement Binding Format est quelque chose d'autre:

L'événement Format se produit chaque fois que la valeur actuelle des changements de BindingManagerBase , qui comprend:

  • La première fois que le prope rty est lié.
  • Chaque fois que la position change.
  • Chaque fois que la liste liée aux données est triée ou filtrée, ce qui est accompli lorsqu'un DataView fournit la liste.

Il semblerait que les feux de l'événement Format chaque fois qu'un changement de propriété de la valeur actuelle.