How to get OnPropertyChanging event when use NotifyPropertyWeaver? - c#

I use NotifyPropertyWeaverMsBuildTask to handle NotifyPropertyChanged for automatic properties. I know OnPropertyChanged() method rise when Property value is changed. But when this method is called value of property is changed and old value is lost. Is there any way to get old value?
tanx.

If you want to use the old value inside the OnPropertyChanged then write it like this
public void OnPropertyChanged(string propertyName, object before, object after)
Then if your code looks like this
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Name { get; set; }
public void OnPropertyChanged(string propertyName, object before, object after)
{
// do something with before/after
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
This will be injected
public class Person : INotifyPropertyChanged
{
private string name;
public event PropertyChangedEventHandler PropertyChanged;
public string Name
{
get { return name; }
set
{
object before = Name;
name = value;
OnPropertyChanged("Name", before, Name);
}
}
public void OnPropertyChanged(string propertyName, object before, object after)
{
// do something with before/after
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
More information is available here https://github.com/SimonCropp/NotifyPropertyWeaver/wiki/BeforeAfter
Does this meet your requirements?

INotifyPropertyChanged doesn't provide a means to capture the previous value of a property; you'd have to implement your own.

Related

The texblock's text doesn't change when i update the property, why?

When I check the property manual, with a message box, it shows the new value.
But it doesn't work for the textblock.
enter image description here
The PropertyChanged event should be raised when the value of that property is set.
class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
field = value;
RaisePropertyChanged(propertyName);
}
}
class StudentViewModel : BaseViewModel
{
private string _messagee;
public string Messagee
{
get => _messagee;
set => SetProperty(ref _messagee, value);
}
}

Bind a Class property to controls Winform - C# [duplicate]

What is the best way to bind a property to a control so that when the property value is changed, the control's bound property changes with it.
So if I have a property FirstName which I want to bind to a textbox's txtFirstName text value. So if I change FirstName to value "Stack" then the property txtFirstName.Text also changes to value "Stack".
I know this may sound a stupid question but I'll appreciate the help.
You must implement INotifyPropertyChanged And add binding to textbox.
I will provide C# code snippet. Hope it helps
class Sample : INotifyPropertyChanged
{
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
firstName = value;
InvokePropertyChanged(new PropertyChangedEventArgs("FirstName"));
}
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void InvokePropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, e);
}
#endregion
}
Usage :
Sample sourceObject = new Sample();
textbox.DataBindings.Add("Text",sourceObject,"FirstName");
sourceObject.FirstName = "Stack";
A simplified version of the accepted answer that does NOT require you to type names of properties manually in every property setter like OnPropertyChanged("some-property-name"). Instead you just call OnPropertyChanged() without parameters:
You need .NET 4.5 minimum.
CallerMemberName is in the System.Runtime.CompilerServices namespace
public class Sample : INotifyPropertyChanged
{
private string _propString;
private int _propInt;
//======================================
// Actual implementation
//======================================
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
//======================================
// END: actual implementation
//======================================
public string PropString
{
get { return _propString; }
set
{
// do not trigger change event if values are the same
if (Equals(value, _propString)) return;
_propString = value;
//===================
// Usage in the Source
//===================
OnPropertyChanged();
}
}
public int PropInt
{
get { return _propInt; }
set
{
// do not allow negative numbers, but always trigger a change event
_propInt = value < 0 ? 0 : value;
OnPropertyChanged();
}
}
}
Usage stays the same:
var source = new Sample();
textbox.DataBindings.Add("Text", source, "PropString");
source.PropString = "Some new string";
Hope this helps someone.

How can I use a dotted path as a property name of a PropertyChangedEventHandler?

How can I use a dotted path as a property name of a PropertyChangedEventHandler?
public class Person
{
private int _age;
public int Age
{
get { return _age;}
set
{
_age = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public partial class MyControl : UserControl, INotifyPropertyChanged
{
public Person Person
{
get { return (Person)GetValue(PersonProperty); }
set { SetValue(PersonProperty, value); }
}
public static DependencyProperty PersonProperty =
DependencyProperty.Register("Person", typeof (Person), typeof (MyControl), null);
private void someMethod()
{
OnPropertyChanged("Person.Age");
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
<TextBox Text="{Binding Person.Age, Mode=TwoWay}"/>
But OnPropertyChanged("Person.Age") cannot resolve the symbol.
Is it possible to use a dotted path as a propertyName of OnPropertyChanged()?
The Age setter, you should always call OnPropertyChanged("Age").
INotifyPropertyChanged isn't meant to be used for sub-properties. You also don't need it on a UserControl, since dependency properties already provide notification. Once you fix your OnPropertyChanged call in the Person class you should be fine.
You have a couple of options to fix the Person.Age setter:
Call OnPropertyChanged("Age") (and remove the = null in the OnPropertyChanged signature.
If you are targeting .NET 4.5 or later, the preferred solution is to change the Person.OnPropertyChanged signature to be OnPropertyChanged(string [CallerMemberName] propertyName = null). Calling OnPropertyChanged() from the Age setter will then fill set propertyName to Age. See the this blog post or the MSDN documentation for more details.

OnPropertyChange does not exist in the current context?

Cant seem to see where I am going wrong? the OnPropertyChange is not being recondnised any suggestions?
public class MedicationList : INotifyPropertyChanged
{
public int MedicationID { get; set; }
public string Description
{
get
{
return Description;
}
set
{
OnPropertyChanged( "Description" );
Description = value;
}
}
}
}
EDIT I have added public class MedicationList : INotifyPropertyChanged
You should implement INotifyPropertyChanged interface, which has single PropertyChanged event declared. You should raise this event if some of object's properties changed. Correct implementation:
public class MedicationList : INotifyPropertyChanged
{
private string _description; // storage for property value
public event PropertyChangedEventHandler PropertyChanged;
public string Description
{
get { return _description; }
set
{
if (_description == value) // check if value changed
return; // do nothing if value same
_description = value; // change value
OnPropertyChanged("Description"); // pass changed property name
}
}
// this method raises PropertyChanged event
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) // if there is any subscribers
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I bet you want to do something like this:
public class MedicationList : INotifyPropertyChanged {
public int MedicationID { get; set; }
private string m_Description;
public string Description {
get { return m_Description; }
set {
m_Description = value;
OnPropertyChanged("Description");
}
}
private void OnPropertyChanged(string propertyName) {
if (string.IsNullOrEmpty(propertyName))
throw new ArgumentNullException("propertyName");
var changed = PropertyChanged;
if (changed != null) {
changed(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
You need the actual code the interface implements inside of your class.
/// <summary>
/// Public event for notifying the view when a property changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises the PropertyChanged event for the supplied property.
/// </summary>
/// <param name="name">The property name.</param>
internal void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
This method needs to be defined by your type to raise the INotifyPropertyChanged::PropertyChanged event
public PropertyChangedEventHandler PropertyChanged;
...
private void OnPropertyChanged(string propertyName) {
var saved = PropertyChanged;
if (saved != null) {
var e = new PropertyChangedEventArgs(propertyName);
saved(this, e);
}
}
There's a difference between a base class and an interface.
With a base class, the members are automatically inherited and one needs to do nothing (except if some members need an override). With an interface, the class does not inherit the interface members automatically; you have to introduce them in your class. If you don't the compiler will complain.
INotifyPropertyChanged is an interface.
You need to inherent BaseViewModel.
public class MedicationList : BaseViewModel

WPF - Implementing System.ComponentModel.INotifyPropertyChanged for Base Class

I'd like to implent the System.ComponentModel.INotifyPropertyChanged interface for a property on a base class, but I'm not quite sure how to hook it up.
Here's the signature for the property I'd like to get notifications for:
public abstract bool HasChanged();
And my code in the base class for handling the change:
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
How do I handle the hookup of the event in the base class without having to call OnPropertyChanged() in each child class?
Thanks,
Sonny
EDIT:
OK... so I think that when the value for HasChanged() changes, I'm supposed to call OnPropertyChanged("HasChanged"), but I'm not sure how to get that into the base class. Any ideas?
Is this what you are after?
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
//make it protected, so it is accessible from Child classes
protected void OnPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
Notice the OnPropertyChanged accessible level is protected. And then in your concrete class or child classes, you do:
public class PersonViewModel : ViewModelBase
{
public PersonViewModel(Person person)
{
this.person = person;
}
public string Name
{
get
{
return this.person.Name;
}
set
{
this.person.Name = value;
OnPropertyChanged("Name");
}
}
}
EDIT: after reading the OP question again, I realize that he does not want to call the OnPropertyChanged in the child class, so I am pretty sure this will work:
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool hasChanged = false;
public bool HasChanged
{
get
{
return this.hasChanged;
}
set
{
this.hasChanged = value;
OnPropertyChanged("HasChanged");
}
}
//make it protected, so it is accessible from Child classes
protected void OnPropertyChanged(String info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
and in child class:
public class PersonViewModel : ViewModelBase
{
public PersonViewModel()
{
base.HasChanged = true;
}
}

Categories