.net c#从子控件检测ViewDidUnload

Detecting ViewDidUnload from a child control
2021-02-23
  •  译文(汉语)
  •  原文(英语)

我试图弄清楚如何可以加入ViewDidUnload控件的超级视图.为了说明为什么需要这个,请考虑我的ControlFactory类,它产生UIButtons(以及其他控件):

internal static class ControlFactory
{
        private static readonly IObservable<Unit> sharedDynamicTypeChanged = TinyIoCContainer.Current
            .Resolve<ISystemNotificationsService>()
            .DynamicTypeChanged
            .Publish()
            .RefCount();

        public static UIButton CreateButton()
        {
            return new DynamicTypeAwareButton(sharedDynamicTypeChanged, UIFont.PreferredHeadline);
        }
}

这里的想法是,UIButton工厂生产的每种产品都将根据用户的动态类型设置自动缩放其字体.我DynamicTypeAwareButton的内部类看起来像这样:

private sealed class DynamicTypeAwareButton : UIButton
{
    private readonly IObservable<Unit> dynamicTypeChanged;
    private readonly UIFont font;
    private IDisposable subscription;

    public DynamicTypeAwareButton(IObservable<Unit> dynamicTypeChanged, UIFont font)
    {
        this.dynamicTypeChanged = dynamicTypeChanged;
        this.font = font;
    }

    public override void MovedToSuperview()
    {
        base.MovedToSuperview();

        // TODO: figure out when to subscribe/unsubscribe
        this.subscription = this.dynamicTypeChanged
            .StartWith(Unit.Default)
            .Subscribe(_ => this.UpdateFont());
    }

    private void UpdateFont()
    {
        this.Font = this.font;
    }
}

如评论中所述,问题是我需要知道何时卸载按钮的超级视图,以便可以处理订阅.我可以轻松访问超级视图,但是在卸载该超级视图时,我找不到任何要通知的钩子.

有谁知道实现这一目标的任何方式?

解决过程1

而不是MovedToSuperView使用WillMoveToSuperView-它会被调用两次,一次是将Button添加到视图(即=>订阅),一次是当Button将被废弃时(此处newSuperview为null).

另外,您可以使用SerialDisposable以下代码更优雅地编写此代码:

private sealed class DynamicTypeAwareButton : UIButton
{
    private readonly IObservable<Unit> dynamicTypeChanged;
    private readonly UIFont font;
    private SerialDisposable subscription = new SerialDisposable();

    public override void WillMoveToSuperView(UIView newView)
    {
        base.WillMoveToSuperView();

        // Whenever SerialDisposable.Disposable is assigned, it throws
        // away the previous one. That means, even if the Button gets
        // moved to a new non-null View, we're still not leaking a 
        // subscription
        if (newView != null) 
        {
            this.subscription.Disposable = this.dynamicTypeChanged
                .StartWith(Unit.Default)
                .Subscribe(_ => this.UpdateFont());
        } 
        else 
        {
            this.subscription.Disposable = Disposable.Empty;
        }
    }

    public void UpdateFont()
    {
        /* ... */
    }
}
速聊1:
太棒了!谢谢保罗.

I'm trying to figure out how I can hook into ViewDidUnload on a control's superview. To illustrate why I need this, consider my ControlFactory class, which produces UIButtons (amongst other controls):

internal static class ControlFactory
{
        private static readonly IObservable<Unit> sharedDynamicTypeChanged = TinyIoCContainer.Current
            .Resolve<ISystemNotificationsService>()
            .DynamicTypeChanged
            .Publish()
            .RefCount();

        public static UIButton CreateButton()
        {
            return new DynamicTypeAwareButton(sharedDynamicTypeChanged, UIFont.PreferredHeadline);
        }
}

The idea here is that every UIButton produced by the factory will automatically scale its font based on the user's dynamic type setting. My DynamicTypeAwareButton is an inner class that looks like this:

private sealed class DynamicTypeAwareButton : UIButton
{
    private readonly IObservable<Unit> dynamicTypeChanged;
    private readonly UIFont font;
    private IDisposable subscription;

    public DynamicTypeAwareButton(IObservable<Unit> dynamicTypeChanged, UIFont font)
    {
        this.dynamicTypeChanged = dynamicTypeChanged;
        this.font = font;
    }

    public override void MovedToSuperview()
    {
        base.MovedToSuperview();

        // TODO: figure out when to subscribe/unsubscribe
        this.subscription = this.dynamicTypeChanged
            .StartWith(Unit.Default)
            .Subscribe(_ => this.UpdateFont());
    }

    private void UpdateFont()
    {
        this.Font = this.font;
    }
}

The problem, as noted in the comment, is that I need to know when the button's superview is unloaded so that I can dispose of the subscription. I can easily get access to the superview, but I can't find any hooks to be notified when that superview is unloaded.

Does anyone know of any way of achieving this?

Solutions1

Instead of MovedToSuperView use WillMoveToSuperView - it will get called twice, once when the Button is added to a View (i.e. => Subscribe), and once when the Button is about to be trashed (where newSuperview will be null).

Also, you can write this a bit more elegantly using SerialDisposable:

private sealed class DynamicTypeAwareButton : UIButton
{
    private readonly IObservable<Unit> dynamicTypeChanged;
    private readonly UIFont font;
    private SerialDisposable subscription = new SerialDisposable();

    public override void WillMoveToSuperView(UIView newView)
    {
        base.WillMoveToSuperView();

        // Whenever SerialDisposable.Disposable is assigned, it throws
        // away the previous one. That means, even if the Button gets
        // moved to a new non-null View, we're still not leaking a 
        // subscription
        if (newView != null) 
        {
            this.subscription.Disposable = this.dynamicTypeChanged
                .StartWith(Unit.Default)
                .Subscribe(_ => this.UpdateFont());
        } 
        else 
        {
            this.subscription.Disposable = Disposable.Empty;
        }
    }

    public void UpdateFont()
    {
        /* ... */
    }
}
Talk1:
Fantastic! Thanks Paul.
转载于:https://stackoverflow.com/questions/23712351/detecting-viewdidunload-from-a-child-control

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入