Reputation: 774
I checked other links here but I can't really get the right answer. I have xaml which consists of two textboxes. The first is hours while the next is minutes. Whenever I change the value of hours in textbox, minutes should reset to 0. How can I do it with OnPropertyChange
?
public class Variable : INotifyPropertyChanged
{
public Variable()
{
this.hours = "1";
this.minutes = "2";
}
public event PropertyChangedEventHandler PropertyChanged;
private string hours;
private string minutes;
public string Hours
{
get { return this.hours.ToString(); }
set
{
if (this.hours != value)
{
this.hours = value;
this.minutes = "0";
this.OnPropertyChanged("Hours");
}
}
}
public string Minutes { get { return this.minutes; } }
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName ));
}
}
Upvotes: 3
Views: 2483
Reputation: 67128
Unless Minutes
textbox is read-only then you should have a setter for that property:
public string Minutes
{
get => this.minutes;
set
{
if (this.minutes != value)
{
this.minutes = value;
OnPropertyChanged();
}
}
}
Now you can use this setter in the Hours
setter to notify UI of the change:
if (this.hours != value)
{
this.hours = value;
this.OnPropertyChanged();
this.Minutes = "0";
}
Instead if Minutes
is correctly a read-only property then you have two options: make its setter private
(and use it as above) or manually call OnPropertyChanged()
to notify UI of the change:
if (this.hours != value)
{
this.hours = value;
this.OnPropertyChanged();
this.minutes = "0";
this.OnPropertyChanged(nameof(Minutes));
}
I'm strongly against the second option because it adds unwanted complexity, I don't want to manually notify changes unless absolutely needed.
All these said you may improve few more things in your code.
OnPropertyChanged()
has a parameter with [CallerMemberName]
attribute then you do not need to specify the property name (if it's invoked from within that property). When you have to (see second example) then use nameof(PropertyName)
instead of "PropertyName"
because it'll be changed automatically when you rename your property.
I don't have a big picture of your code but if Hours
and Minutes
are integer property then you should have int
instead of string
. If input is wrong you'd better to inform user as soon as possible. Also you should validate values:
if (value < 0 || value >= 60)
throw new ArgumentOutOfRangeException(...);
Not in this case but generally when you have a property where the backing field is there only because you do not have a setter then you can use:
public string Minutes { get; private set; }
Upvotes: 5
Reputation: 1486
Simply call the OnPropertyChanged
invoker again with the name Minutes
OnPropertyChanged(nameof(Minutes));
Or you can add a private setter to the minutes property that invokes it there. So you'll have something like this:
public class Variable : INotifyPropertyChanged
{
public Variable()
{
this.hours = "1";
this.minutes = "2";
}
public event PropertyChangedEventHandler PropertyChanged;
private string hours;
private string minutes;
public string Hours
{
get { return this.hours.ToString(); }
set
{
if (this.hours != value)
{
this.hours = value;
this.OnPropertyChanged();
this.Minutes = "0";
}
}
}
public string Minutes
{
get { return this.minutes; }
private set
{
if(this.minutes == value)
return;
this.minutes = value;
OnPropertyChanged()
}
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName ));
}
}
By the way, The [CallerMemberName]
attribute in the invoker means that if you don't pass the parameter any value, it'll take the name of whoever called it. In case of a property, it'll be the name of that property, so you don't have to write it.
Upvotes: 2