问题
When the Text
property of a TextBox
is bound to an object property which that object implements INotifyPropertyChanged
, the event PropertyChanged
may fire two times while having the same value:
1) when the text is changed inside the TextBox
2) when the control is leaving from it.
Consider these methods of a form:
private void Form1_Load(object sender, EventArgs e)
{
TextBox textBox = new TextBox();
TextBox secondTextBox = new TextBox();
secondTextBox.Location = new Point(0, 100);
this.Controls.Add(textBox);
this.Controls.Add(secondTextBox);
MyClass instance = new MyClass();
instance.PropertyChanged += instance_PropertyChanged;
textBox.DataBindings.Add("Text", instance, "Id", true, DataSourceUpdateMode.OnPropertyChanged);
}
private void instance_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine(e.PropertyName + " changed");
}
and the back-end class:
private class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int _id;
public int Id
{
get
{
return _id;
}
set
{
_id = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Id"));
}
}
}
To reproduce the problem, type something in the upper textbox, check the console, and then enter the lower textbox and check again the console. Upon leaving, a property change is reported. Why?
回答1:
The default value of Binding.DataSourceUpdateMode property is OnValidation. In this configuration the data source is being only updated when Validating event occurs. In your example you use OnPropertyChanged mode, so you additionally request update of the data source whenever the text is changed inside the TextBox.
It is the default behaviour i.e. the Binding class was implemented in this way. If you want more details, you can examine Binding.Target_PropertyChanged and Binding.Target_Validate methods with a reflector.
From my perspective this behaviour isn't a problem but you need to change the implementation of the setter in the following way:
set
{
if(_id != value)
{
_id = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Id"));
}
}
Even if we assume that the implementation of Binding class is wrong, I think that it is a good practise to check whether a value has changed before generating PropertyChanged event.
回答2:
Based on Michal's answer, I found the solution in switching off the CausesValidation
property of TextBox
as:
textBox.CausesValidation = false;
来源:https://stackoverflow.com/questions/20457670/textbox-leave-causes-propertychanged-get-fired-twice