C# 有没有一种方法可以通过反应式UI订阅所有层次结构属性更改?

C# 有没有一种方法可以通过反应式UI订阅所有层次结构属性更改?,c#,wpf,reactiveui,C#,Wpf,Reactiveui,关于问题:() 我当前在父反应对象中有一个子反应对象 public class Child : ReactiveObject { private string propertyX public string PropertyX { get { return this.propertyX; } set { this.RaiseAndSetIfChanged(x => x.PropertyX, ref this.propertyX, value);

关于问题:()

我当前在父反应对象中有一个子反应对象

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); }
    }
}
我的问题是,我必须写:

this.WhenAny(x => x.Child.PropertyX, x => x.Value).Subscribe(x => raisePropertyChanged("Child"));
每个孩子的财产

我需要这样做的原因是,由于嵌套属性绑定,我的DevExpress网格将不会更新

<dxg:GridColumn x:Key="PropertyX" Header="PropertyX" FieldName="Child.PropertyX" />

因此,这有点像黑客攻击,但您始终可以“转发”属性:

this.WhenAny(x => x.Child.PropertyX, x => x.Value).ToProperty(this, x => x.PropertyXFromChild, out propertyXFromChild);

您可以尝试使用表达式树。在(我认为)RxUI6最近发生变化之前,这一直对我有效。目前,它适用于某些属性类型

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); }
//        }
}
void Main()
{
var o1=新的反应人();
foreach(Functions.GetProperties()中的var元素)
{
o1.ObservableForProperty(element).Subscribe(x=>string.Format(“属性:{0}正在更改为{1}”,x.GetPropertyName(),x.Value).Dump();//注意Dump()方法是用于LinqPad的(http://www.linqpad.net/)。如果需要,请使用console.log或类似工具。
}
//两处物业均已登记
o1.FirstName=“珍妮”;
o1.FirstName=“彼得”;
o1.FirstName=“Dave”;
o1.LastName=“彼得森”;
o1.LastName=“琼斯”;
o1.LastName=“史密斯”;
}
公共静态类函数{
公共静态IList GetProperties()
{
var result=新列表();
var properties=typeof(T).GetProperties()。其中(pi=>pi.GetCustomAttributes(typeof(DataMemberAttribute),false).Any());
foreach(属性中的var属性)
{
var p=表达式参数(typeof(T),“p”);
//var prop=Expression.Convert(Expression.Property(p,Property),typeof(Object));
//注意,我认为您应该使用expression.convert行,它允许您处理Int32s等。然而,我“认为”RxUI6中有一个but阻止了它。https://github.com/reactiveui/ReactiveUI/issues/659
var prop=Expression.Property(p,Property);//试试这个
var keySelector=Expression.Lambda(prop,p);
结果。添加(键选择器);
}
返回结果;
}
}
公共类ReactivePerson:ReactiveObject
{
[IgnoreDataMember]
字符串_firstName;
[数据成员]
公共字符串名{
获取{return\u firstName;}
设置{this.RaiseAndSetIfChanged(ref _firstName,value);}
}
[IgnoreDataMember]
字符串_lastName;
[数据成员]
公共字符串姓氏{
获取{return\u lastName;}
设置{this.RaiseAndSetIfChanged(ref{u lastName,value);}
}
//int不工作,请参阅Functions.GetProperties中的注释。
//[IgnoreDataMember]
//国际年龄;
//[数据成员]
//公共信息{
//获取{return\u age;}
//设置{this.RaiseAndSetIfChanged(ref _age,value);}
//        }
}

您能详细解释最后一部分吗?我不清楚您想用DevExpress网格做什么DevExpress网格不更新具有嵌套属性绑定的框架元素。所以我必须创建一个wheny订阅来传播inotifypropertyChanged。这是他们的一个局限,我想知道ReactiveUI是否有一个聪明的解决方案。这就解释了吗?这是否意味着我必须将嵌套属性包装到父属性中?我必须创建一个名为PropertyXFromChild.Yep的属性,但如果DevXPress无法找到其他方法,我看不出您还能做什么。。