PropertyChangedEvent firing multiple times - c#

I have a class with several properties. When these are changed, a PropertyChangedEvent raised. Some properties depend on other properties, so when one of the dependencies is changed, it raises a PropertyChangedEvent for itself, and for the property that depends on it.
My problem is, that I have attached a PropertyChangedEventHandler to an instance of this class. When one of the properties that is depended upon by another property, this event handler is called several times. Is there a way to get around this?
UPDATE
A little code, just to illustrate what I'm talking about:
private bool _foo;
private bool _bar;
public bool Foo
{
get { return _foo; }
set
{
_foo = value;
OnPropertyChanged("Foo");
OnPropertyChanged("Baz");
}
}
public bool Bar
{
get { return _bar; }
set
{
_bar = value;
OnPropertyChanged("Bar");
OnPropertyChanged("Baz");
}
}
public bool Baz
{
get
{
return Foo && Bar;
}
}
When Foo is set, Baz changes as well. If I attach a PropertyChangedEventHandler, this will be called twice, when I set Foo. I only want to call it once. Is there a nice way around it?

All you need to do is think logically about this issue for a moment to get your answer. You have the following situation:
public bool Foo
{
get { return _foo; }
set
{
_foo = value;
OnPropertyChanged("Foo");
OnPropertyChanged("Baz");
}
}
public bool Bar
{
get { return _bar; }
set
{
_bar = value;
OnPropertyChanged("Bar");
OnPropertyChanged("Baz");
}
}
public bool Baz
{
get
{
return Foo && Bar;
}
}
My first comment is that if you are going to raise your INotifyPropertyChanged.PropertyChanged event more than once at a time, then you'd be better off using an implementation like this, which would enable you to raise the event for as many properties as you like at once:
protected virtual void NotifyPropertyChanged(params string[] propertyNames)
{
if (PropertyChanged != null)
{
foreach (string propertyName in propertyNames)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
...
NotifyPropertyChanged("Foo", "Bar");
So back to your problem... let's think about your requirement:
You need to notify the interface when the value of Baz changes.
Its value can be changed when either the Foo or Bar property values change... therefore you'll need to notify the interface when either of them changes, as you have.
Now, #Franck commented to say that You should from the setter of Property 1 trigger a method to update Property 2 which by changing will trigger his own property change. Let's think about that for a minute... presumably, you'd need to call this same method from both of the Foo or Bar property setters to make it work.
However, what would actually happen is that the when the Foo and Bar values are changed, the method would be called twice and so the INotifyPropertyChanged notification will still be called twice, albeit now coming from the Baz setter... so clearly, this is no improvement.
There is however, one more option that could work for you. For this to work, you'd need to add a helper method that would update the Foo or Bar property values and notify the INotifyPropertyChanged interface on behalf of the Baz property:
public void UpdateBaz(bool? foo, bool? bar)
{
if (foo != null) Foo = foo;
if (bar != null) Bar = bar;
OnPropertyChanged("Baz");
}
Of course, for this to work, you'd need to remove the call to OnPropertyChanged("Baz") from the two property handlers:
public bool Foo
{
get { return _foo; }
set { _foo = value; OnPropertyChanged("Foo"); }
}
public bool Bar
{
get { return _bar; }
set { _bar = value; OnPropertyChanged("Bar"); }
}
However, if you want the Foo and Bar properties to be updated through Binding, then you'd be back to #Franck's suggestion of calling this method twice and the two properties are updated individually. In that case, it seems as though you'll just have to put up with the Baz property being notified twice.

insert a value changed check in your setter like:
set
{
if(value != [yourfield])
{
yourfield = value;
OnPropertyChanged(Yourfield);
}
}

Related

How to get notification of a third party object's property change event?

I have a third part class object called SomeOnesClass and int property count has only get, I cannot change or extend this class, it doesn't have InotificationChanged implementation, How to get the notification for count value change only with instance of SomeOnesClass.
Try putting SomeOnesClass into another class, use properties to access SomeOnesClass and raise the event in the setter. E.g.
class SomeOnesClassNotification : INotifyPropertyChanged {
public SomeOnesClassNotification(SomeOnesClass someOnesClass) {
this.someOnesClass = someOnesClass;
}
private SomeOnesClass someOnesClass;
private int count;
public int Count {get {return count; }
set {count = value;
NotifyCountChanged();
}
}
void NotifyCountChanged() {
// Do stuff
}
public event PropertyChangedEventHandler PropertyChanged;
}
I'm not too sure of how to implement InotificationChanged, but hopefully this will give you an idea. Note you'd have to use properties or methods to access each of the SomeOnesClass members.

Using INotifyPropertyChanged in a Class

C# allows the creation of a property as below:
public string SomeRandomText
{
get; set;
}
The framework handles the creation of the backing variable for this property. How can I have such a property and still have change notification?
Is this allowed in a class that implements INotifyPropertyChanged?
public string SomeRandomTextBeingNotified
{
get;
set
{
NotifyPropertyChanged("SomeRandomTextBeingNotified");
}
}
You can't use automatic properties when trying to use this. You'll need to creating a backing store:
private string _someRandomText;
public string SomeRandomText {
get { return _someRandomText; }
set
{
_someRandomText = value;
NotifyPropertyChanged("SomeRandomText");
}
}
To make code look cleaner, you can use attributes for INotifyPropertyChanged.
Easy usage of INotifyPropertyChanged with Property-Attribute
Have a look at this Use of Attributes... INotifyPropertyChanged
Actually you can, but you basically need to change the bytecode post C# compiler.
This may sound like a lot of work, but this is one of the easier postprocessing steps that for example PostSharp includes.
http://www.sharpcrafters.com/solutions/notifypropertychanged
http://www.sharpcrafters.com/blog/post/Recording-Automate-INotifyPropertyChanged-with-Karol-Waledzik-from-Internetium.aspx
A lot more functionality is available ;)
Otherwise note that
enter code hereenter code here`NotifyPropertyChanged("SomeRandomTextBeingNotified");
is bad code. I do all that in one field update method:
set
{
OnUpateField (ref _someRandomText, value);
}
The update method does all - check for equality (you do NOT want to trigger when new value = old value), then trigger updates as needed. It gets the property name through the calling method third parameter that is automatically set by the compiler. Alternatives are using a LINQ statement ( ref someRandomText, value, this->SomeRandomText). I never would love a string there that does not get renamed on refactoring ;)
If you don't have a base class, something like this is cake and very flexible:
public class NotificationObject : INotifyPropertChanged
{
private readonly Dictionary<string, object> Properties = new Dictionary<string, object>();
public event PropertyChangedEventHandler PropertyChanged;
protected TType Get<TType>(string propertyName)
{
object value;
return Properties.TryGetValue(propertyName, out value) ? (TType)value : default(TType);
}
protected void Set<TType>(TType value, string propertyName, params string[] dependantPropertyNames)
{
Properties[propertyName] = value;
OnPropertyChanged(propertyName);
if (dependantPropertyNames != null)
{
foreach (string dependantPropertyName in dependantPropertyNames)
{
OnPropertyChanged(dependantPropertyName);
}
}
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArts(propertyName));
}
}
}
This can be used like this:
public SomeObjectThatNeedsToNotifySomething : NotificationObject
{
public int SomeValue
{
get { return Get<int>("SomeValue"); }
set { Set<int>(value, "SomeValue", "SomeAggregateValue"); }
}
public int SomeOtherValue
{
get { return Get<int>("SomeOtherValue"); }
set { Set<int>(value, "SomeOtherValue", "SomeAggregateValue"); }
}
public int SomeAggregateValue
{
get { return SomeValue + SomeOtherValue; }
}
}
If you already have a base class and need to just implement the INotifyPropertyChanged interface, #Rob is correct, provide a backing field and fire the event.
There is no such thing as semi-automatic properties. Nevertheless, there are quite a few ways to implement INotifyPropertyChanged that don't require the burdensome imperative code.
1) Mentioned before: PostSharp, an aspect oriented and commercial project.
2) Creating a Castle DynamicProxy solution. A sample can be found here, actually there's plenty of others out there.
It's worthwhile investing some time in a generic solution, the boilerplate code can get vexing after a while and is prone to errors.

Caliburn - PropertyChanged for child ViewModel

I'm using Caliburn and the MVVM pattern in a WPF application, and am trying to use as many conventions as possible. One issue I'm running into is when I have to wire-up some property-changed notifications on an imported class.
Say I have a ViewModel like so:
class ViewModelA
{
private readonly IViewModelB _b;
public ViewModelA(IViewModelB b)
{
_b = b;
}
public bool CanGo
{
get { return _b.MyBoolProperty; }
}
public void Go()
{
//Does something here
}
}
What is the recommended (correct) way to call NotifyOfPropertyChange(() => CanGo) when the PropertyChanged event for MyBoolProperty is fired off ViewModelB?
In the past I've used a PropertyObserver type class to manage this.
Or am I designing this scenario completely wrong?
If your "sub"-model is exposed with a public property, you could use DependenciesAttribute to track changes:
class ViewModelA
{
public IViewModelB B {get; private set;}
public ViewModelA(IViewModelB b)
{
B = b;
}
public bool CanGo
{
get { return B.MyBoolProperty; }
}
[Dependencies("B.MyBoolProperty")]
public void Go()
{
//Does something here
}
}
To work properly, the whole property path should be composed of notifying objects.
You can also put a final "*"
[Dependencies("B.*")]
to indicate that all properties of B should cause the precondition re-evaluation; note that "*" only acts on the end of the proprerty path and just for one level of depth (it doesn't track changes on sub-models of B).

How to create XAML like path bindings in C#

The XAML {Binding} construct is very handy because it handles all of the PropertyChanged issues automatically. It is really impressive when you hand it a path to an object, through .NET data structures, and everything is automatically updated for you.
I would like to use the same thing in C#. I would like to have a property that is derived from the value of another property. Example
class Foo
{
public Bar Bar = new Bar();
public string ItGetter
{
get
{
return Bar.Baz.It;
}
}
}
class Bar
{
public Baz Baz = new Baz();
}
class Baz
{
public string It { get { return "You got It!"; } }
}
If you call ItGetter on a Foo, you get the It value from Baz. This works fine, except that it is not invalidated--i.e., if It changed, there would be no change notifications on the ItGetter. Furthermore, if the Foo.Bar or Bar.Baz references are changed, you would also not get change noficiations.
I can add the appropriate IChangeNotify code on the properties, but my question is: How do I code the ItGetter property such that it will call its PropertyChanged event when any of the references in the path, or the It value change? I'm hoping I don't have to manually setup property changed events on all the items in the path....
Thanks for any help!
Eric
You could take a look at dependancy properties. They allow you to define properties in the WPF property system that are backed with stacks of metadata and a detailed value resolution system.
Importantly for you they allow they allow you to register for property changed events, and they allow you to make values dependant on other stuff.
There are some other good artcile around such as 'Demystifying dependency properties' by Josh Smith and 'Dependency Properties' by Christian Mosers
You might also want to read Dependency Property Callbacks and Validation
Here is the full code that does what I was looking for, using Dependency Properties, as Simon mentioned:
// This class exists to encapsulate the INotifyPropertyChanged requirements
public class ChangeNotifyBase : DependencyObject, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public class Foo : ChangeNotifyBase
{
public Foo()
{
Bar = new Bar();
var binding = new Binding("Bar.Baz.It");
binding.Source = this;
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(this, ItGetterProperty, binding);
}
/// <summary>
/// The ItGetter dependency property.
/// </summary>
public bool ItGetter
{
get { return (bool)GetValue(ItGetterProperty); }
set { SetValue(ItGetterProperty, value); }
}
public static readonly DependencyProperty ItGetterProperty =
DependencyProperty.Register("ItGetter", typeof(bool), typeof(Foo));
// Must do the OnPropertyChanged to notify the dependency machinery of changes.
private Bar _bar;
public Bar Bar { get { return _bar; } set { _bar = value; OnPropertyChanged("Bar"); } }
}
public class Bar : ChangeNotifyBase
{
public Bar()
{
Baz = new Baz();
}
private Baz _baz;
public Baz Baz { get { return _baz; } set { _baz = value; OnPropertyChanged("Baz"); } }
}
public class Baz : ChangeNotifyBase
{
private bool _it;
public bool It { get { return _it; } set { _it = value; OnPropertyChanged("It"); } }
}
If you now register for events on ItGetter, you will get notified if any of these things change:
Baz.It
Foo.Bar (I.e., change the reference)
Bar.Baz " "
If you set on of the object references (Foo.Bar or Bar.Baz) to null, the value of ItGetter changes to false.

Making mocks trigger PropertyChanged when changed

I am using RhinoMocks, and I have a Mock which has a property I need to behave as a real property - updating its value when set, and also trigger PropertyChanged when the property is changed.
The interface of the mocked object is in essence this:
public interface IFoo
{
event PropertyChangedEventHandler PropertyChanged;
int Bar { get; set; }
}
When creating the mock I set PropertyBehavior - which makes it actually update its faked value:
var mocks = new MockRepository();
var fakeFoo = mocks.DynamicMock<IFoo>();
SetupResult.For(fakeFoo.Bar).PropertyBehavior();
But when I update the value PropertyChanged isn't triggered. Now, the interface doesn't implement the INotifyPropertyChanged interface as it is an interface.. How can I make PropertyChanged triggered?
The role of listener and mutator may sometimes be combined in the same class (e.g. in an adapter), but both roles should not be tested together.
In one test, you merely verify that your listening class reacts to the PropertyChanged event as designed. You don't care about what caused the property to change in that test:
[Test]
public void Updates_Caption_when_Bar_PropertyChanged()
{
var foo = MockRepository.GenerateStub<IFoo>();
foo.Bar = "sometestvalue1";
var underTest = new UnderTest(foo);
// change property and raise PropertyChanged event on mock object
foo.Bar = "sometestvalue2";
foo.Raise(x=>x.PropertyChanged+=null,
foo,
new PropertyChangedEventArgs("Bar"));
// assert that the class under test reacted as designed
Assert.AreEqual("sometestvalue2", underTest.Caption);
// or if the the expected state change is hard to verify,
// you might just verify that the property was at least read
foo.AssertWasCalled(x => { var y = foo.Bar; } );
}
In another test, you verify that your class plays its mutator role as designed:
[Test]
public void Reset_clears_Foo_Bar()
{
var foo = MockRepository.GenerateStub<IFoo>();
foo.Bar = "some string which is not null";
var underTest = new UnderTest(foo);
underTest.Reset();
// assert that the class under test updated the Bar property as designed
Assert.IsNull(foo.Bar);
}
This way, it is never necessary to put real logic into your mock objects like you are trying to do. This does require that you design your classes for testability; it is hard to add such tests to existing classes. Hence the practice of test driven development.
I'm not an expert in RhinoMocks, but I wouldn't try to do that with any of the mock-framework I know (TypeMock I know the most).
I would implement something like:
public class FooFake: IFoo
{
public event PropertyChangedEventHandler PropertyChanged;
int _bar;
public int Bar
{
set
{
if( PropertyChanged != null )
PropertyChanged();
_bar = value;
}
get
{
return _bar;
}
}
}
Sorry. Nothing really clever. But I like this kind of stub as they can be resused.

Categories