is there a way to subscribe to all hierachical property changes with Reactive UI?
Asked Answered
V

2

6

Referring to question: (Is there a pattern for subscribing to hierarchical property changes with Reactive UI?)

I currently have a child reactiveobject in my parent reactiveobject.

public class Child : ReactiveObject
{
 private string propertyX
 public string PropertyX
    {
        get { return this.propertyX; }
        set { this.RaiseAndSetIfChanged(x => x.PropertyX, ref this.propertyX, value); }
    }

 private string propertyY
 public string PropertyY
    {
        get { return this.propertyY; }
        set { this.RaiseAndSetIfChanged(x => x.PropertyY, ref this.propertyY, value); }
    }
}

public class Parent: ReactiveObject
{

 public Parent(Child child)
 {
   Child = child;
   this.WhenAny(x => x.Child.PropertyX, x => x.Value).Subscribe(x => raisePropertyChanged("Child"));
 }

 private Child child
 public Child Child
    {
        get { return this.child; }
        set { this.RaiseAndSetIfChanged(x => x.Child, ref this.child, value); }
    }
}

My question is that do I have to write:

this.WhenAny(x => x.Child.PropertyX, x => x.Value).Subscribe(x => raisePropertyChanged("Child"));

for each child property?

The reason I need to do this is because my DevExpress grid will not update because of the nested property binding.

<dxg:GridColumn x:Key="PropertyX" Header="PropertyX" FieldName="Child.PropertyX" />
Vintner answered 2/8, 2013 at 15:13 Comment(2)
Can you explain the last part more? I'm not clear what you are trying to do with your DevExpress GridDishpan
DevExpress grid does not update the framework elements that have a nested property binding. So I have to create a WhenAny subscription to propagate the inotifypropetychanged. Its a limitation on their part that I was wonder if ReactiveUI has a clever solution for it. Does that explain it?Vintner
D
1

So, it's a bit of a hack, but you can always "forward" a property:

this.WhenAny(x => x.Child.PropertyX, x => x.Value).ToProperty(this, x => x.PropertyXFromChild, out propertyXFromChild);
Dishpan answered 7/8, 2013 at 22:53 Comment(2)
Wont this imply that I have to wrap the nested property into the parent? I would have to create a property called PropertyXFromChild.Vintner
Yep, but if DevExpress won't figure out any other way I don't see what else you can do..Dishpan
C
0

You could try something with expression trees. This was working for me until (I think) a recent change in RxUI6. For now it's working for certain property types.

void Main()
{
    var o1 = new ReactivePerson();

    foreach (var element in Functions.GetProperties<ReactivePerson>())
    {
        o1.ObservableForProperty(element).Subscribe(x=>string.Format("property: {0} is changing to {1}",  x.GetPropertyName(), x.Value).Dump()); // note that the Dump() method is for LinqPad (http://www.linqpad.net/). Use console.log or similar if needed.
    }

    // Both properties registered
    o1.FirstName = "Jenny";
    o1.FirstName = "Peter";
    o1.FirstName = "Dave";
    o1.LastName = "Peterson";
    o1.LastName = "Jones";
    o1.LastName = "Smith";
}

public static class Functions{
    public static IList<Expression<Func<T,object>>> GetProperties<T>()
    {
        var result = new List<Expression<Func<T,object>>>();
        var properties = typeof(T).GetProperties().Where(pi => pi.GetCustomAttributes(typeof(DataMemberAttribute), false).Any());
        foreach (var property in properties)
        {
            var p = Expression.Parameter(typeof(T), "p");
            //var prop = Expression.Convert(Expression.Property(p, property), typeof(Object)); 
            // Note I think that you should use the expression.convert line, which allows you to handle Int32s etc. However, I 'think' that there's a but in RxUI6 which is blocking it. https://github.com/reactiveui/ReactiveUI/issues/659
            var prop = Expression.Property(p, property); // try this instead
            var keySelector = Expression.Lambda<Func<T, object>>(prop, p);
            result.Add(keySelector);
        }
        return result;
    }
}
public class ReactivePerson : ReactiveObject
{

        [IgnoreDataMember] 
        string _firstName;
        [DataMember] 
        public string FirstName{
            get { return _firstName; }
            set { this.RaiseAndSetIfChanged(ref _firstName, value); }
        }

        [IgnoreDataMember] 
        string _lastName;
        [DataMember] 
        public string LastName{
            get { return _lastName; }
            set { this.RaiseAndSetIfChanged(ref _lastName, value); }
        }

//      int not working, see comment in Functions.GetProperties.        
//      [IgnoreDataMember] 
//      int _age;
//        [DataMember] 
//      public int Age{
//            get { return _age; }
//            set { this.RaiseAndSetIfChanged(ref _age, value); }
//        }
}
Cloutier answered 28/8, 2014 at 10:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.