Best way to make Dependency Properties into Observables?
-
Thursday, November 19, 2009 2:34 PM
Ive posted this previously on c9 ut i think i'll have better reach here :)
ive been experimienting with converting DependencyProperties to Observables and this is what ive come up with:public class DependencyObservable<T> : IDisposable {
EventHandler eh;
DependencyPropertyDescriptor des;
object instance;
public DependencyObservable( IObserver<T> observer, DependencyProperty dp, Type ownertype, object ins ) {
des = DependencyPropertyDescriptor.FromProperty( dp, ownertype );
instance = ins;
eh = new EventHandler( ( o, e ) => observer.OnNext( ( T )des.GetValue( instance ) ) );
des.AddValueChanged( instance, eh );
} public void Dispose( ) {
des.RemoveValueChanged( instance, eh );
}
}
public static class WindowExtensions {
public static IObservable<double> HeightAsObservable( this MainWindow w ) {
return Observable.CreateWithDisposable<double>( obs => new DependencyObservable<double>( obs, MainWindow.HeightProperty, w.GetType( ), w ) );
}
}and here is an example of using the extension method,
public MainWindow( ) {
InitializeComponent( );
Observable.Context = SynchronizationContext.Current;
this.HeightAsObservable( ).Subscribe( d => label1.Content = d );
}is there anything i should do diffrent? should i call onCompleted in dispose for example? is there a way to do it more elegantly, perhaps without a helper class?
ive tested this approach with binding and animation and it seems to work- Edited by Allan Lindqvist Wednesday, November 25, 2009 3:13 PM
All Replies
-
Thursday, November 19, 2009 3:47 PMHi Al,
will have to play with this a bit before being able to see if I can propose any changes. For now, take a look at our IPropertyGetter/IPropertySetter interfaces in System.CoreEx and the various conversion to and from Obseravble/Observer of these interfaces in Observable and Observer.
Jeffrey -
Monday, November 23, 2009 5:19 PM
I would love to know this as well. It would be nice if there was a method perhaps like:
public static IObservable<IEvent<DependencyPropertyChangedEventArgs>> ToObservable(this DependencyObject object, DependencyProperty property) { ... } // or public static IObservable<IEvent<PropertyChangedEventArgs<T>>> ToObservable<T>(this DependencyObject object, DependencyProperty property) // where T is property.PropertyType { ... }which could be used like:// using System.Windows.Controls; var button = new Button(); var buttonHeightChanged = button.ToObservable(Button.HeightProperty); // or var buttonHeightChanged = button.ToObservable<double>(Button.HeightProperty);
Thoughts? -
Tuesday, November 24, 2009 1:21 PM
After watching Eriks excelent pdc talk i found that you can actually do this without a helper class, check out this extension method for the Height property:
public static IObservable<double> HeightAsObservable( this MainWindow w ) { return Observable.Create<double>( o => { var des = DependencyPropertyDescriptor.FromProperty( MainWindow.HeightProperty, typeof( MainWindow ) ); var eh = new EventHandler( ( s, e ) => o.OnNext( ( double )des.GetValue( w ) ) ); des.AddValueChanged( w, eh ); return ( ) => des.RemoveValueChanged( w, eh ); } ); }
you could also generelize it to all Dependecy properties like this:
public static IObservable<T> ToObservable<T>( this DependencyObject dependencyObject, DependencyProperty property ) { return Observable.Create<T>( o => { var des = DependencyPropertyDescriptor.FromProperty( property, dependencyObject.GetType( ) ); var eh = new EventHandler( ( s, e ) => o.OnNext( ( T )des.GetValue( dependencyObject ) ) ); des.AddValueChanged( dependencyObject, eh ); return ( ) => des.RemoveValueChanged( dependencyObject, eh ); } ); }
using the above extension method, you can do what vcomrhencke wants, modded from my original post:
this.ToObservable<double>( MainWindow.HeightProperty )
Alternativly, the method above can be an observable of object.
i havent tested this with attatched propertis but in theory that should work :P
it does work with regular DPs though and also works with animation and bindings
any comments are welcome :)- Marked As Answer by Allan Lindqvist Wednesday, November 25, 2009 8:15 AM
-
Tuesday, November 24, 2009 1:48 PM
i did a little test and this approach also seems to work with attatched properties like this:
rectangle.ToObservable<double>( Canvas.LeftProperty ).Subscribe( d => label2.Content = d );
where rectangle is in a canvas and the Canvas.Left is bound to something (a slider that is two-way bound to the window height i my case)- Marked As Answer by Allan Lindqvist Wednesday, November 25, 2009 8:17 AM
-
Tuesday, November 24, 2009 2:11 PMOh, now that is quite awesome! :)That totally made my day. Excellent work, aL! :)
-
Tuesday, November 24, 2009 2:30 PMmy pleasure :)
id love to hear from someone on the team if they have any comments or if i butcher their api ;) -
Wednesday, November 25, 2009 12:23 AM
You definitely don't butcher the API. I would probably rewrite DependencyObservable as:IObservable<T> FromDependencyProperty<T>(object target, DependencyProperty property) { // argument checking return Observable.Create<T>(o => { var d = DependencyPropertyDescriptor.FromProperty(property, target.GetType()); var h = new EventHandler((o, e) => observer.OnNext((T)d.GetValue(target))); d.AddValueChanged(target, h); return () => d.RemoveValueChanged(target, h); }); }- Marked As Answer by Allan Lindqvist Wednesday, November 25, 2009 8:15 AM
-
Wednesday, November 25, 2009 8:10 AM
cool, thanks :)
why not an extension method though? and why on object and not dependecyobject?
i think some version or other of this method would be great to have built into Rx, wpf is the future after all :) -
Wednesday, November 25, 2009 6:55 PMDependency object would be better you are right. If it is dependency object then I think it could be an extension method. It is generally in bad taste to add extension methods that apply to every object.
-
Wednesday, November 25, 2009 7:11 PMThis would make an excellent addition to Rx. It would be great if a future version had something like this. :)
-
Saturday, January 02, 2010 7:51 AM
Hi,
Please see my response in the following thread. It works on dependency properties, INotifyPropertyChanged implementations, and also the [Property]Changed event pattern.
http://social.msdn.microsoft.com/Forums/en-US/rx/thread/36bf6ecb-70ea-4be3-aa35-b9a9cbc9a078
- Dave
http://davesexton.com/blog- Marked As Answer by Allan Lindqvist Sunday, January 03, 2010 6:31 PM

