10

我从博客中查看了 ReactiveUi 的示例,我想知道 ReactiveUI 在下面是否有某种订阅管理工具,或者这些示例是否忽略了它们可能会泄露订阅的事实?

每当我在 ReactiveUi 中调用导致 的方法时IDisposable,我是否需要保留该引用并自己跟踪它?这是否也意味着我的 ViewModel 需要是一次性的,这似乎很困难,因为我们真的不知道 WPF 中连接的“视图”何时消失(即我的 ViewModel 是否反映了数据网格中的项目)所以似乎没有合适的调用处置的地方。

4

3 回答 3

15

您还必须记住,由 Rx 和 ReactiveUI 返回的 IDisposables 与非托管内存无关——它们只是简单的 .NET 对象,仍由垃圾收集器引用。

您在 ReactiveObjects 的构造函数中进行的大多数订阅都将与宿主对象的生命周期相关联 - 因此,当它超出范围并受 GC 影响时,所有订阅也会如此,CLR 将检测循环引用并只是核爆一切。

正如 Enigmativity 所提到的,一个棘手的问题是当您使用 FromEventPattern 将 Subscription(可能还有 ViewModel)的生命周期与 WPF 对象的生命周期联系起来时。但是,我认为如果您经常在 ReactiveUI 中使用 FromEventPattern,那么您肯定是在做错事™。

RxUI 都是关于 ViewModels 的,而 ViewModels 都是关于命令属性的(以及连接属性如何相互关联),因此您可以将用户体验的行为与其视觉效果分开测试。

于 2012-01-26T07:32:55.953 回答
12

如果您需要提前IDisposable取消订阅observable,您只需要保留对订阅返回的引用。当 Observable 被or消息终止时,它们自然会调用。DisposeOnCompletedOnError

但是,当您拥有无限的可观察订阅(即FromEventPattern)时,您确实需要保留引用,但这与在关闭表单/视图之前需要删除事件处理程序完全相同。

于 2012-01-19T00:41:11.460 回答
2

为了安全起见,我将从现在开始使用这种模式。我可能会修改为通过扩展方法工作,但原则是合理的。为确保您不会泄露您想要删除的订阅

class Mesh2D{

    public Mesh2D()
    {
        DisposeOnUnload(CreateBindings());
    }

    // Register all disposables for disposal on
    // UIElement.Unload event. This should be
    // moved to an extension method.
    void DisposeOnUnload(IEnumerable<IDisposable> disposables)
    {
        var d = new CompositeDisposable(disposables);
        var d2 = this.UnloadedObserver()
            .Subscribe(e => d.Dispose());
        var d3 = this.Dispatcher.ShutdownStartedObserver()
            .Subscribe(e => d.Dispose());
        d.Add(d2);
        d.Add(d3);
    }

    // Where your bindings are simply yielded and
    // they are removed on Unload magically
    IEnumerable<IDisposable> CreateBindings()
    {
        // When the size changes we need to update all the transforms on 
        // the markers to reposition them. 
        yield return this.SizeChangedObserver()
            .Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler)
            .Subscribe(eventArgs => this.ResetImageSource());

        // If the points change or the viewport changes
        yield return this.WhenAny(t => t.Mesh, t => t.Viewport, (x, t) => x.Value)
            .Throttle(TimeSpan.FromMilliseconds(20), RxApp.DeferredScheduler)
            .Subscribe(t => this.UpdateMeshChanged());
    }
}

请注意,我使用自动生成的扩展方法包装 RX FromEventPattern,因此我免费获得 SizeChangedObserver() 和 UnloadedObserver(),而不是难记的 FromEventPattern 格式。

包装代码是这样生成的

public static IObservable<EventPattern<RoutedEventArgs>> UnloadedObserver(this FrameworkElement This){
    return Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(h => This.Unloaded += h, h => This.Unloaded -= h);
}

上述模式也可能用于解除 IDisposable 视图模型的绑定。

于 2013-03-26T16:43:04.310 回答