maui-linux/Xamarin.Forms.Core/TemplateUtilities.cs

129 строки
3.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
namespace Xamarin.Forms
{
internal static class TemplateUtilities
{
public static async Task<Element> FindTemplatedParentAsync(Element element)
{
if (element.RealParent is Application)
return null;
var skipCount = 0;
element = await GetRealParentAsync(element);
while (!Application.IsApplicationOrNull(element))
{
var controlTemplated = element as IControlTemplated;
if (controlTemplated?.ControlTemplate != null)
{
if (skipCount == 0)
return element;
skipCount--;
}
if (element is ContentPresenter)
skipCount++;
element = await GetRealParentAsync(element);
}
return null;
}
public static Task<Element> GetRealParentAsync(Element element)
{
Element parent = element.RealParent;
if (parent is Application)
return Task.FromResult<Element>(null);
if (parent != null)
return Task.FromResult(parent);
var tcs = new TaskCompletionSource<Element>();
EventHandler handler = null;
handler = (sender, args) =>
{
tcs.TrySetResult(element.RealParent);
element.ParentSet -= handler;
};
element.ParentSet += handler;
return tcs.Task;
}
public static void OnContentChanged(BindableObject bindable, object oldValue, object newValue)
{
var self = (IControlTemplated)bindable;
var newElement = (Element)newValue;
if (self.ControlTemplate == null)
{
for (var i = 0; i < self.InternalChildren.Count; i++)
{
self.InternalChildren.Remove(self.InternalChildren[i]);
}
if (newValue != null)
self.InternalChildren.Add(newElement);
}
else
{
if (newElement != null)
{
BindableObject.SetInheritedBindingContext(newElement, bindable.BindingContext);
}
}
}
public static void OnControlTemplateChanged(BindableObject bindable, object oldValue, object newValue)
{
var self = (IControlTemplated)bindable;
// First make sure any old ContentPresenters are no longer bound up. This MUST be
// done before we attempt to make the new template.
if (oldValue != null)
{
var queue = new Queue<Element>(16);
queue.Enqueue((Element)self);
while (queue.Count > 0)
{
ReadOnlyCollection<Element> children = queue.Dequeue().LogicalChildrenInternal;
for (var i = 0; i < children.Count; i++)
{
Element child = children[i];
var controlTemplated = child as IControlTemplated;
var presenter = child as ContentPresenter;
if (presenter != null)
presenter.Clear();
else if (controlTemplated == null || controlTemplated.ControlTemplate == null)
queue.Enqueue(child);
}
}
}
// Now remove all remnants of any other children just to be sure
for (var i = 0; i < self.InternalChildren.Count; i++)
{
self.InternalChildren.Remove(self.InternalChildren[i]);
}
ControlTemplate template = self.ControlTemplate;
if (template == null)
{
// do nothing for now
}
else
{
var content = template.CreateContent() as View;
if (content == null)
{
throw new NotSupportedException("ControlTemplate must return a type derived from View.");
}
self.InternalChildren.Add(content);
}
}
}
}