Xamarin ContentView / View生命周期

时间:2018-03-21 00:14:07

标签: c# xaml xamarin xamarin.forms

Xamarin.Android 8.2

Xamarin.Forms 2.5

简短的问题

我如何或者应该让ContentView知道其包含页面的生命周期状态(例如,出现,消失,睡眠)

长问题

我正在学习如何创建可重用的Xamarin ContentView。我决定创建一个控件<LabelCarousel/>,它将一个接一个地显示其子标签。 问题是我不知道如何停止切换内容的后台计时器

样品

Sample

用法

<local:LabelCarousel>
    <Label>Hello</Label>
    <Label>Hola</Label>
</local:LabelCarousel>

实施

namespace XamarinStart.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    [ContentProperty("LabelContainer")]
    public partial class LabelCarousel : ContentView
    {
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        [Description("Labels"), Category("Data")]
        public List<Element> LabelContainer { get; } = new List<Element>();

        private int _index = 0;
        private Timer _timer = new Timer(2000);

        public LabelCarousel ()
        {
            InitializeComponent ();

            _timer.Elapsed += TimerEvent;
            _timer.Start();

        }

        private void TimerEvent(object sender, ElapsedEventArgs e)
        {
            if (_index >= LabelContainer.Count)
            {
                _index = 0;
            }

            var selected = LabelContainer[_index++];
            ChangeLabel((Label)selected);
        }

        private void ChangeLabel(Label lbl)
        {
            Device.BeginInvokeOnMainThread(async () =>
            {
                await this.FadeTo(0);
                Content = lbl;
                await this.FadeTo(1);
            });
        }
    }
}

问题

当我将此应用程序置于后台或推送另一个活动时,计时器仍在运行,浪费CPU资源。当父页面改变状态时,是否有任何好主意让可重用的ContentView通知?

相关文章

https://forums.xamarin.com/discussion/38989/contentview-lifecycle https://forums.xamarin.com/discussion/65140/we-need-a-way-for-contentview-and-viewcells-to-monitor-their-own-lifecycle

谢谢!

1 个答案:

答案 0 :(得分:2)

我通过使用类扩展来为所有AttachLifecycleToPage对象添加Element方法,从而找到了一种可能性。

基本上,扩展背后的原则是沿着UI树追踪Parent。但是,当启动ContentView(即调用ctor)时,它可能尚未附加到父级,或者其父级(如果有)未附加到页面。这就是为什么我听Element的PropertyChanged事件,其Parent是暂时为null。元素连接后,搜索过程将继续。 请注意AttachLifecycleToPage在Element ctor中不应该是同步的,这将导致死锁。

扩展代码

namespace XamarinStart.Extensions
{
    public static class PageAwareExtension
    {
        public static void AttachLifecycleToPage(this Element element, EventHandler onAppearing = null,
            EventHandler onDisappearing = null)
        {
            var task = new Task(() =>
            {
                var page = GetPage(element);
                if (page == null)
                {
                    return;
                }

                if (onAppearing != null)
                {
                    page.Appearing += onAppearing;
                }

                if (onDisappearing != null)
                {
                    page.Disappearing += onDisappearing;
                }
            });
            task.Start();
            return;
        }
        public static Page GetPage(this Element element, int timeout = -1)
        {
            if (element is Page) return (Page)element;

            Element el = element;
            // go up along the UI tree
            do
            {
                if (el.Parent == null)
                {
                    // either not attached to any parent, or no intend to attach to any page (is that possible?)
                    var signal = new AutoResetEvent(false);
                    PropertyChangedEventHandler handler = (object sender, PropertyChangedEventArgs args) =>
                    {
                        // https://github.com/xamarin/Xamarin.Forms/blob/master/Xamarin.Forms.Core/Element.cs
                        // Setting Parent property is tracked
                        Element senderElement = (Element) sender;
                        if (args.PropertyName == "Parent" && senderElement.Parent != null)
                        {
                            signal.Set();
                        }
                    };
                    el.PropertyChanged += handler;

                    var gotSignal = signal.WaitOne(timeout);
                    if (!gotSignal)
                    {
                        throw new TimeoutException("Cannot find the parent of the element");
                    }

                    el.PropertyChanged -= handler;
                } // if parent is null

                el = el.Parent;

            } while (! (el is Page));

            return (Page) el;
        }
    }
}

修改后的LabelCarousel

    public LabelCarousel ()
    {
        InitializeComponent ();

        _timer.Elapsed += TimerEvent;
        _timer.Start();

        this.AttachLifecycleToPage(OnAppearing, OnDisappearing); 
    }
    private void OnDisappearing(object sender, EventArgs eventArgs)
    {
        _timer.Stop();
    }

    private void OnAppearing(object sender, EventArgs eventArgs)
    {
        _timer.Start();
    }

好吧,我不确定这个肮脏的黑客是否会引起一些副作用。我希望最终正式版本能够让ContentView获得完整的生命周期支持。