If I have a class like so:
public class MyClass:INotifyPropertyChanged
{
private Visibility isVisible;
private ObservableCollection<string> names;
public Visibility IsVisible
{
get{ return isVisible;}
set { isVisible = value; OnPropertyChanged("IsVisible");}
}
public ObservableCollection<string> Names
{
get { return names;}
set { names = value; OnPropertyChanged("Names");}
}
//ctor
public MyClass(){
names = new ObservableCollection<string>();
}
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Before any one beheads me - I have done quite a bit of looking up and have found a mixed bag of answers...
Do I modify the public or private properties/variables for use in my bindings? i.e. I have an issue where adding to names collection will trigger OnPropertyChanged and changing isVisible will NOT trigger OnPropertyChanged. My assumption is that this is because names is an ObservableCollection where as isVisible is not but I am not sure...
If I am supposed to uses the public properties - what is the need for having the private ones?
You don't need a private property, only a private field would be enough so replace:
private Visibility isVisible {get; set;}
with
private Visibility isVisible;
If I am supposed to uses the public properties - what is the need for
having the private ones?
You cannot use Auto-properties with INotifyPropertyChanged. That is why you need a backing field for your property IsVisible.
See: An elegant way to implement INotifyPropertyChanged
So I think you are confusing Properties and Fields (aka variables).
public class Example()
{
public int FieldExample;
private int _propertyExample;
public int PropertyExample
{
get
{
return _propertyExample;
}
set
{
_propertyExample = value;
}
}
}
In simple usage scenarios, the difference between a field and a property isn't obvious. But properties have different plumbing under the hood that allows them to take advantage of reflection and binding. For WPF, this means you've got to have public properties. Best practice for a Public Property is associate it with a private (or protected) field - and that field name is usually either prefixed with an _ and/or starts with lower case character. This is called a "backing field."
The private backing field holds the actual data, the public property is just the means by which other classes can interact with that data. Inside the get and set blocks, you can place any code you want: instead of returning my backing field, I could instead put: return 5;. It's not useful, and it's poor practice, but I can. Generally, the code that resides in your get and set blocks should still set or get the value; although you might validate the input first, and/or format it first. The pattern you are implementing in your sets for WPF raises an event that the property has changed. Other parts of your program are listening for that event so they know to update the UI.
So in your code, if you only change the backing field and don't raise an event that there has been a change, the UI will not update. You might desire this behavior if you are performing a complex action on an object, and want to hold off performing an UI update until a complete batch of items are finished, but that's an optimization and for starters you are probably better off always accessing/setting to the Public Property.
Related
I am trying to implement INotifyPropertyChanged for a lot of classes, and each of these classes have lots and lots of properties. I have been following this MSDN documentation for how to implement INofifyPropertyChanged, but their instructions don't seem to be practical in cases where a class has many many properties.
Currently most of my properties use the short hand:
public DateTime? DateClosed { get; set; }
But the documentation says that i need to add the following to each setter method:
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("DateClosed");
This means that I then need to declare a body for the get method and declare private variables to handle the actual getting and setting of properties. Like this:
private DateTime? _dateOfIncident = null;
public DateTime? DateClosed
{
get { return _dateOfIncident; }
set
{
_dateOfIncident= value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("DateClosed");
}
}
Does anyone know a way around this?
A few classes can easily be changed to implement INotifyPropertyChanged. But since you state you have a lot of classes with a lot of properties, it's a real burden to get this done manually or even with templates.
What you really need is a tool that does it for you, so I present you Fody and it's NotifyPropertyChanged plugin. What Fody does is weave some extra code in between your code at compile time. The only thing you have to do is add a single attribute on the classes you want to implement INotifyPropertyChanged and the rest is done for you.
[ImplementPropertyChanged]
public class Person
{
public string GivenNames { get; set; }
public string FamilyName { get; set; }
public string FullName
{
get
{
return string.Format("{0} {1}", GivenNames, FamilyName);
}
}
}
I'm not sure you're going to find a workaround here. Auto-properties, as you're using them now, are really just a compiler shorthand that get's converted to full properties with a backing field eventually anyway (at least, as I understand it).
The use of INPC is a routine that's sorta separate and apart from the duty of a normal property. It's notifying subscribers (usually, your view XAML) that the property in question has changed or is changing.
tl;dr -- you're not going to get around having to rewrite autoproperties to full properties with backing fields. But toolkits like MVVMLight have some great Visual Studio code snippets to make this relatively fast. Eventually you can even do this:
private string _someString;
public string SomeString
{
get { return _someString;}
set
{
//Set returns bool, so you can trigger other logic on it!
Set(() => SomeString, ref _someString, value);
}
}
This gives you some neat features:
Strong naming (unlike the magic string in your example)
Set only triggers INPC event if the value is different
Set returns boolean so you can perform more action if the value changed
MVVMLight is nice in that you don't have to use all its features, or even implement MVVM pattern. It just has a lot of nice 'tools' you can leverage.
There are a lot of patterns to do it, or you can buy a tool like PostSharp that will do it for you.
For example, here is one method of doing it:
public abstract class BaseNotifyPropertyChanged : INotifyPropertyChanged
{
private Dictionary<string, object> _valueStore = new Dictionary<string, object>();
public event PropertyChangedEventHandler PropertyChanged;
protected T Get<T>([CallerMemberName]string property = null)
{
object value = null;
if (!_valueStore.TryGetValue(property, out value))
return default(T);
return (T)value;
}
protected void Set<T>(T value, [CallerMemberName]string property = null)
{
_valueStore[property] = value;
OnPropertyChangedInternal(property);
}
protected void OnPropertyChanged([CallerMemberName]string property = null)
{
OnPropertyChangedInternal(property);
}
private void OnPropertyChangedInternal(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Which you then inherit from your classes:
public class PlainOldObject : BaseNotifyPropertyChanged
{
public int MyProperty
{
get { return Get<int>(); }
set { Set(value); }
}
}
Which takes care of the backing store and everything for you. You may want to add logic to only call the OnPropertyChangedInternal if the property actually changed (compare references or value), but I'll leave that as an exercise for you.
Simply use the Observable Object class. Instead of creating a DateTime property, you'd create an ObservableObject<DateTime> and you would just bind to DateClosed.Value.
To implement data binding in WPF, according to MS a "class needs to provide the proper property changed notifications." [ref here]
AFAIK, part of setting this up means taking the following steps, if not already set up in the class (ref this article on MSDN):
When properties are changed, they need call to a method to raise an event.
This means auto-implemented properties must be changed so they use a private backing field, so set can change the property and also call the method to raise an event.
The class needs to implement INotifyPropertyChanged.
The class needs to declare the PropertyChangedEventHandler event.
The event needs to be raised in something like this:
...
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
If I already have many existing classes that do not take any of these steps, what is the best way to change these classes so they change only so far as is needed to make them meet these standards?
If you want the minimum-possible-code-impact solution, then you want the Fody PropertyChanged weaver. This is installed as a NuGet package with Install-Package PropertyChanged.Fody, or through the VS package manager dialogue.
Once installed, you can mark a class with the [ImplementPropertyChanged] attribute, and your job is basically done. The weaver will add the relevant event calls at compile time by manipulating the generated IL, which means that you don't have to explicitly implement the interface or the event calls in code. You can keep your auto-implemented property syntax, too!
The linked docs provide details of more advanced cases but, in my experience, the out-of-box behaviour is sufficient for almost all needs.
I love this implementation with [CallerMemberName] in C# 5 as described here
protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
...
}
Just make the parameter optional and decorate it with the CallerMemberName attribute.
Your property now looks like this:
public DateTime Time
{
get { return this.model.DateTime; }
set
{
this.model.DateTime = value;
NotifyPropertyChanged();
}
}
i usually like to use this implementation to notify the changes in my properties
class IWillNotifyYou : INotifyPropertyChanged
{
private int _firstProperty;
public int FirstProperty
{
get { return _firstProperty; }
set
{
if (value != _firstProperty)
{
_firstProperty = value;
OnPropertyChanged("FirstProperty");
}
}
}
private string _secondProperty;
public string SecondProperty
{
get { return _secondProperty; }
set
{
if (value != _secondProperty)
{
_secondProperty = value;
OnPropertyChanged("SecondProperty");
}
}
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
note that you could create a specialized event with the name of the property like FirstPropertyChanged
You'll need to identify what role your existing classes play now. WPF is most beneficial using MVVM (Model-View-ViewModel). Identifying the role of your current classes will help determine what needs to be changed (if anything).
Assuming your existing classes are Business Objects, it is up to you to decide whether or not you even need to implement INotifyPropertyChanged. WPF is easiest to work with by binding to ViewModel. The ViewModel is what actually handles the data between the View (WPF screen) and the Model.
The Model can implement INotifyPropertyChanged, but it does not have to. The ViewModel will hold whatever properties are needed for that specific screen (or control) and is probably the path you will want to explore so you do not completely 180* your existing business objects.
Add ": INotifyPropertyChanged" after your class definition:
Public class Test : INotifyPropertyChanged
{
}
Accept ReSharpers recommendation to implement the interface for this class (you might have to install ReSharper for this to work).
Then, in the setter for any property, add this:
OnPropertyChanged("PropertyName")
This means that you can now bind properties in the XAML to this property in this class.
Let's just say that I have:
public Boolean booleanValue;
public bool someMethod(string value)
{
// Do some work in here.
return booleanValue = true;
}
How can I create an event handler that fires up when the booleanValue has changed? Is it possible?
Avoid using public fields as a rule in general. Try to keep them private as much as you can. Then, you can use a wrapper property firing your event. See the example:
class Foo
{
Boolean _booleanValue;
public bool BooleanValue
{
get { return _booleanValue; }
set
{
_booleanValue = value;
if (ValueChanged != null) ValueChanged(value);
}
}
public event ValueChangedEventHandler ValueChanged;
}
delegate void ValueChangedEventHandler(bool value);
That is one simple, "native" way to achieve what you need. There are other ways, even offered by the .NET Framework, but the above approach is just an example.
INotifyPropertyChanged is already defined to notify if property is changed.
Wrap your variable in property and use INotifyPropertyChanged interface.
Change the access of the BooleanValue to private and only allow changing it through one method for consistency.
Fire your custom event in that method
.
private bool _boolValue;
public void ChangeValue(bool value)
{
_boolValue = value;
// Fire your event here
}
Option 2: Make it a property and fire the event in the setter
public bool BoolValue { get { ... } set { _boolValue = value; //Fire Event } }
Edit: As others have said INotifyPropertyChanged is the .NET standard way to do this.
Perhaps take a look at the INotifyPropertyChanged interface. You're bound to come across it's use again in future:
MSDN: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
CallingClass.BoolChangeEvent += new Action<bool>(AddressOfFunction);
In your class with the bool property procedure:
public event Action<bool> BoolChangeEvent;
public Boolean booleanValue;
public bool someMethod(string value)
{
// Raise event to signify the bool value has been set.
BoolChangeEvent(value);
// Do some work in here.
booleanValue = true;
return booleanValue;
}
No it is not possible* to get notified about for changes in value of a variable.
You can achieve almost what you want by making the value to be a property of some class and fire events on change as you wish.
*) if your code is debugger for a process you can make CPU to notify you about changes - see data chage breakpoints in Visual Studio. This will require at least some amount of native code and harder to implement correctly for manged code due to hance of objects to be moved in memory by GC.
I have a simple usercontrol (WinForms) with some public properties. When I use this control, I want to databind to those properties with the DataSourceUpdateMode set to OnPropertyChanged. The datasource is a class which implements INotifyPropertyChanged.
I'm aware of the need to create bindings against the properties and I'm doing that.
I assumed that my usercontrol would have to implement an interface, or the properties would need to be decorated with some attribute, or something along those lines.But my research has come up blank.
How should this be accomplished? At the moment I'm doing it by calling OnValidating() in my usercontrol whenever a property changes, but that doesn't seem right.
I can get validation to happen if I set the CausesValidation to true on the usercontrol, but that's not very useful to me. I need to validate each child property as it changes.
Note this is a WinForms situation.
EDIT: Evidently I have no talent for explanation so hopefully this will clarify what I'm doing. This is an abbreviated example:
// I have a user control
public class MyControl : UserControl
{
// I'm binding to this property
public string ControlProperty { get; set; }
public void DoSomething()
{
// when the property value changes, the change should immediately be applied
// to the bound datasource
ControlProperty = "new value";
// This is how I make it work, but it seems wrong
OnValidating();
}
}
// the class being bound to the usercontrol
public class MyDataSource : INotifyPropertyChanged
{
private string sourceProperty;
public string SourceProperty
{
get { return sourceProperty; }
set
{
if (value != sourceProperty)
{
sourceProperty = value;
NotifyPropertyChanged("SourceProperty");
}
}
}
// boilerplate stuff
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public class MyForm : Form
{
private MyControl myControl;
public MyForm()
{
// create the datasource
var dataSource = new MyDataSource() { SourceProperty = "test" };
// bind a property of the datasource to a property of the usercontrol
myControl.DataBindings.Add("ControlProperty", dataSource, "SourceProperty",
false, DataSourceUpdateMode.OnPropertyChanged); // note the update mode
}
}
(I have tried this using a BindingSource, but the result was the same.)
Now what I want to happen is that when the value of MyControl.ControlProperty changes, the change is immediately propagated to the datasource (the MyDataSource instance). To achieve this I call OnValidating() in the usercontrol after changing the property. If I don't do that, I have to wait until validation gets triggered by a focus change, which is the equivalent of the "OnValidation" update mode, rather than the desired "OnPropertyUpdate" validation mode. I just don't feel like calling OnValidating() after altering a property value is the right thing to do, even if it (kind of) works.
Am I right in assuming the calling OnValidating() is not the right way to do this? If so, how do I notify the datasource of the ControlProperty change?
I think I've got this figured out. I didn't understand how change notifications were sent from control to bound datasource.
Yes, calling OnValidating() is the wrong way.
From what I've pieced together, there are two ways a control can notify the datasource that a property has changed.
One way is for the control to implement INotifyPropertyChanged. I had never done this from the control side before, and I thought only the datasource side of the binding had to implement it.
When I implemented INotifyPropertyChanged on my user control, and raised the PropertyChanged event at the appropriate time, it worked.
The second way is for the control to raise a specific change event for each property. The event must follow the naming convention: <propertyname>Changed
e.g. for my example it would be
public event EventHandler ControlPropertyChanged
If my property was called Foo, it would be FooChanged.
I failed to notice the relavent part of the MSDN documentation, where it says:
For change notification to occur in a
binding between a bound client and a
data source, your bound type should
either:
Implement the INotifyPropertyChanged
interface (preferred).
Provide a change event for each
property of the bound type.
This second way is how all existing WinForms controls work, so this is how I'm doing it now. I use INotifyPropertyChanged on my datasource, but I raise the Changed events on my control. This seems to be the conventional way.
Implementing the INotifyPropertyChanged interface is very simple. Here is a sample that shows an object with a single public field...
public class Demo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
private string _demoField;
public string DemoField
{
get {return demoField; }
set
{
if (value != demoField)
{
demoField = value;
NotifyPropertyChanged("DemoField");
}
}
}
}
Then you would create a Binding instance to bind a control property to a property (DemoField) on your source instance (instance of Demo).
I want to know, if the value of any of the private or public fields has changed.
Is there any way other than over-riding GetHashCode() or calculating CRC?
The algorithm should be fast too.
Normally, this would be done with the INotifyPropertyChanged interface (link). It is really only practical to use it with properties, though, not fields. However, you could create a private property for each of your private fields. Once you have everything as a property, edit the setter so that you check if the value has changed, then call NotifyPropertyChanged() if it has.
Example:
public event PropertyChangedEventHandler PropertyChanged;
private int _foo;
public int Foo
{
get { return _foo; }
set
{
if (_foo != value)
{
_foo = value;
NotifyPropertyChanged("Foo");
}
}
}
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
You may want to encapsulate all your data (which you want to monitor for change) inside the get/set accessors (a.k.a. properties).
Then, in set accessor, check if value has changed, set it to new value, and:
set _dirty to true (if you need to check it later)
or
raise some event to your liking
Some notes on CRC - even if you have non-colliding CRC/HASH algoritam for your object, you must have original hash somewhere. But simple hashes are likely to duplicate, so you again have speed issue.
If it needs to work for any type and needs to detect any modification, with no false negatives or false positives, I don't see any better way than a copy of all field values for reference. Since you need it to be fast, I would recommend the following:
Write a routine that uses reflection to perform a shallow copy of all field values.
Write a routine that compares the fields by value (if you're looking for changes in nested structures, like arrays or collections, your problem is much tougher.)
Once the above work, you can use IL Emit and write code that does the Reflection once and emits code for the shallow-copy and comparison operations. Now you have some DynamicMethod instances you can use for each operation. These are quite fast, once emitted and jitted.
Insert in every public setter a boolean value, like m_IsChanged, then using a public getter only to check if one of the properties has been changed.
Example:
private bool m_IsChanged = false;
private double m_DoubleValue;
//[...] all other private properties
public double DoubleValue
{
get { return m_DoubleValue; }
set
{
if(m_DoubleValue != value)
m_IsChanged = true;
m_DoubleValue = value;
}
}
//[...] all other getters/setters
public bool IsChanged
{
get { return m_IsChanged; }
}