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
谢谢!
答案 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;
}
}
}
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获得完整的生命周期支持。