C# 反序列化后IReactiveDerivedList已断开

C# 反序列化后IReactiveDerivedList已断开,c#,serialization,json.net,reactiveui,C#,Serialization,Json.net,Reactiveui,当我创建一个带有ReactiveList和IReactiveDerivedList的ViewModel,然后使用Json.net对其进行序列化和反序列化时,派生列表似乎被破坏了。我做错了什么 viewmodel: [DataContract] public class TestViewModel : ReactiveObject { [DataMember] public ReactiveList<int> List { get; } = new ReactiveLi

当我创建一个带有
ReactiveList
IReactiveDerivedList
的ViewModel,然后使用Json.net对其进行序列化和反序列化时,派生列表似乎被破坏了。我做错了什么

viewmodel:

[DataContract]
public class TestViewModel : ReactiveObject
{
    [DataMember]
    public ReactiveList<int> List { get; } = new ReactiveList<int>();

    public IReactiveDerivedList<int> DerivedList { get; }

    public TestViewModel()
    {
        //DerivedList contains all elements of List that are greater than 0.
        DerivedList = List.CreateDerivedCollection(v => v, v => v > 0);
    }
}
[DataContract]
公共类TestViewModel:ReactiveObject
{
[数据成员]
public ReactiveList List{get;}=new ReactiveList();
公共IReactiveDerivedList DerivedList{get;}
公共TestViewModel()
{
//DerivedList包含列表中大于0的所有元素。
DerivedList=List.CreateDerivedCollection(v=>v,v=>v>0);
}
}
序列化测试:

private void Example()
{
    TestViewModel vm = new TestViewModel();
    vm.List.Add(0);
    vm.List.Add(1);

    //vm.DerivedList now has 1 item

    string json = JsonConvert.SerializeObject(vm);
    TestViewModel clone = JsonConvert.DeserializeObject<TestViewModel>(json);

    //vm.DerivedList now has 1 item
    //clone.DerivedList now has 1 item

    vm.List.Add(1);
    clone.List.Add(1);

    //vm.DerivedList now has 2 items
    //clone.DerivedList now has 1 item
}
private void示例()
{
TestViewModel vm=新的TestViewModel();
vm.List.Add(0);
vm.List.Add(1);
//vm.DerivedList现在有1项
字符串json=JsonConvert.SerializeObject(vm);
TestViewModel clone=JsonConvert.DeserializeObject(json);
//vm.DerivedList现在有1项
//clone.DerivedList现在有1项
vm.List.Add(1);
克隆.列表.添加(1);
//vm.DerivedList现在有2项
//clone.DerivedList现在有1项
}

我认为这里的问题是,当ViewModel被反序列化时,用作派生列表源的ReactiveList也被反序列化,这就是问题所在

当您的TestViewModel被反序列化时,事件的顺序如下:

  • 跑步。这是可观测的背景场
  • TestViewModel构造函数将运行。这将设置派生集合,该集合订阅ReactiveList上的可观察对象
  • 回调将运行。这将再次覆盖可观察的支持字段,覆盖其以前的值
最后一步是问题发生的地方。派生集合订阅了旧的可观察对象,而不是ReactiveList现在使用的那些。解决此问题的一种方法是为派生列表属性提供一个私有setter,实现一个,然后在该回调中创建派生列表

[DataContract]
public class TestViewModel : ReactiveObject
{
    [DataMember]
    public ReactiveList<int> List { get; } = new ReactiveList<int>();

    public IReactiveDerivedList<int> DerivedList { get; private set; }

    public TestViewModel()
    {
        SetupRx();
    }

    [OnDeserialized]
    internal void OnDeserialized(StreamingContext context)
    {
        SetupRx();
    }

    private void SetupRx()
    {
        DerivedList?.Dispose();
        DerivedList = List.CreateDerivedCollection(v => v, v => v > 0);
    }
}
[DataContract]
公共类TestViewModel:ReactiveObject
{
[数据成员]
public ReactiveList List{get;}=new ReactiveList();
公共IReactiveDerivedList DerivedList{get;private set;}
公共TestViewModel()
{
SetupRx();
}
[已序列化]
内部已序列化(StreamingContext上下文)
{
SetupRx();
}
私有void SetupRx()
{
DerivedList?.Dispose();
DerivedList=List.CreateDerivedCollection(v=>v,v=>v>0);
}
}

经过更多测试后,即使使用此设置,ReactiveList似乎也有点问题。例如:如果在示例中使用viewmodel类型替换整数,并将筛选器设置为VM类型的属性,则派生列表将再次中断。在SetupRx()中将ChangeTrackingEnabled设置为true没有帮助。当您首先将ChangeTrackingEnabled设置为false,然后再次设置为true时,它确实起作用。在内部,这是因为_itemChanged在ReactiveList的setupRx()中被替换,切换changetracking会重置绑定。但这会产生一些非常丑陋的代码