Problem with Observable2.FromPropertyChangedPattern

Topics: General, Reactive (Rx)
Aug 26, 2011 at 11:52 PM

Hi, I am experiencing some problem with Observable2.FromPropertyChangedPattern method. Seems I am using it wrong - it gives me StackOverflow exception.

Here is my ViewModel class

 

    class TestViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }

        private double _hours;
        public double Hours
        {
            get { return _hours; }
            set
            {
                _hours = value;
                RaisePropertyChanged("Hours");
            }
        }

        private double _days;
        public double Days
        {
            get { return _days; }
            set
            {
                _days = value;
                RaisePropertyChanged("Days");
            }
        }

        public TestViewModel()
        {
            Observable.Return(Hours)
                .Merge(
                    Observable2.FromPropertyChangedPattern(this, tvm => tvm.Hours))
                .Subscribe(_ => Days = Hours/8);
        }
    }

 

And here is code that uses it:

    class Program
    {
        static void Main(string[] args)
        {
            TestViewModel vm = new TestViewModel();

            vm.Hours = 16;
        }
    }

 

And that gives me StackOverflow expection. What am I doing wrong?

Coordinator
Aug 27, 2011 at 4:43 AM
Edited Aug 27, 2011 at 4:57 AM

Hi,

Thanks for reporting this issue.  It's definitely a bug in our code.

When the FromPropertyChangedPattern method detects the INotifyPropertyChanged interface it subscribes, but I had forgotten to add a Where clause that filters out notifications for other properties.

Your Subscribe method sets the Days property, which causes your PropertyChanged event to be raised, causing FromPropertyChangedPattern to incorrectly push a notification that Hours has changed, hence the stack overflow.

I'll fix the problem for the next release.  But for now, there are a few workarounds you can use:

  1. Adjust your Days property so that it only raises PropertyChanged when its value actually changes.

    public double Days
    {
    	get { return _days; }
    	set
    	{
    		if (_days != value)
    		{
    			_days = value;
    			RaisePropertyChanged ("Days");
    		}
    	}
    }
  2. Instead of INotifyPropertyChanged, derive from DependencyObject and change your properties to DependencyProperty.  (See WPF docs for examples.  Note that property changed events on DependencyProperty is not supported in Rxx for Silverlight.)
  3. Instead of INotifyPropertyChanged, use the *Changed event pattern.  For example:

    class TestViewModel
    {
    	public event EventHandler HoursChanged = delegate { };
    	public event EventHandler DaysChanged = delegate { };
    
    	private double _hours;
    	public double Hours
    	{
    		get { return _hours; }
    		set
    		{
    			_hours = value;
    			HoursChanged (this, EventArgs.Empty);
    		}
    	}
    
    	private double _days;
    	public double Days
    	{
    		get { return _days; }
    		set
    		{
    			_days = value;
    			DaysChanged (this, EventArgs.Empty);
    		}
    	}
    
    	public TestViewModel()
    	{
    		Observable.Return(Hours)
    			.Merge(
    				Observable2.FromPropertyChangedPattern(this, tvm => tvm.Hours))
    			.Subscribe(_ => Days = Hours/8);
    	}
    }
    

- Dave

Coordinator
Aug 27, 2011 at 4:46 AM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Aug 27, 2011 at 2:54 PM
Edited Aug 27, 2011 at 2:55 PM

Thank you for detailed and quick response. I will probably wait for release, because I adopted easier and smaller version of "IObservable from INotifyPropertyChanged" method from one topic at one forum (dont remember exactly now), and it does the trick for now, but obviously I would like to use some contributed code, not to create bicycle 100 times

 

> Adjust your Days property so that it only raises PropertyChanged when its value actually changes.
While that is valid option, it is arguable to check or not check for property actual change before sending notification. I am yet to explore the real-world differences through.


About

> the *Changed event pattern
Sorry my incompetence, is that some official way of notifying propert changes? Or it was designed for for this Rxx method?

Coordinator
Aug 27, 2011 at 4:53 PM

Hi,

There are still a few more things that we're working on for Rxx 1.2, although I don't think it's going to be too long before it's released.

But I'm curious, what is easier about the version that you've adopted?  Or do you just mean that it's easier to use because you don't have to work around any bugs?  :P

>> the *Changed event pattern
> Sorry my incompetence, is that some official way of notifying propert changes? Or it was designed for for this Rxx method?

It's official, although perhaps not very well-known.  It was designed as part of the original .NET 1.0 BCL (or perhaps 1.1) for the ComponentModel APIs.  It's used in Visual Studio designers, the PropertyGrid control and custom WinForms applications.  Although, as you can see from my example usage, it's still certainly a viable option for applications today.  Unfortunately, it doesn't seem to work in WPF bindings, although it works great in business objects and is arguably better than INotifyPropertyChanged.

More information:

http://msdn.microsoft.com/en-us/library/3b8tbfec.aspx

- Dave