【问题标题】:Xamarin ContentView/View LifecycleXamarin 内容视图/视图生命周期
【发布时间】:2018-03-21 00:14:07
【问题描述】:

版本

Xamarin.Android 8.2

Xamarin.Forms 2.5

小问题

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

长问题

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

示例

用法

<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

谢谢!

【问题讨论】:

    标签: c# xaml xamarin xamarin.forms


    【解决方案1】:

    我自己想出了一种可能性,方法是使用类扩展将AttachLifecycleToPage 方法添加到所有Element 对象。

    基本上,扩展背后的原理是沿着 UI 树跟踪父级。但是,当 ContentView 被启动(即调用 ctor)时,它可能还没有附加到父级,或者它的父级(如果有)没有附加到页面。这就是为什么我要监听其 Parent 暂时为空的 Element 的 PropertyChanged 事件。一旦元素被附加,搜索过程就会继续。 注意 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;
            }
        }
    }
    

    修改后的标签轮播

        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。

    【讨论】:

      猜你喜欢
      • 2012-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-30
      • 2013-08-11
      • 1970-01-01
      相关资源
      最近更新 更多