Skip to content

Commit

Permalink
feat: Enable AOT compatibility (#157)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreamescaper authored Nov 6, 2024
1 parent 2e98dad commit d1a26a1
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 64 deletions.
2 changes: 1 addition & 1 deletion src/BlazorBindings.Core/BlazorBindings.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<Description>Common logic for using Blazor to target native renderers. For mobile app projects for Android and iOS use the BlazorBindings.Maui package.</Description>
<PackageTags>blazor;blazorbindings</PackageTags>
<ImplicitUsings>enable</ImplicitUsings>
<IsTrimmable>true</IsTrimmable>
<IsAotCompatible>true</IsAotCompatible>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/BlazorBindings.Maui/BlazorBindings.Maui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<Title>Maui binding for Blazor</Title>
<Description>Maui Blazor Bindings enables using Blazor syntax in .razor files to build native apps for iOS and Android.</Description>
<PackageTags>blazor;blazorbindings</PackageTags>
<IsTrimmable>true</IsTrimmable>
<IsAotCompatible>true</IsAotCompatible>

<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">10.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ private int AddTemplateGroup()
void INonPhysicalChild.SetParent(object parentElement)
{
var parent = (TControl)parentElement;
var dataTemplate = new DataTemplateSelector(TemplateSelector, AddTemplateGroup, AddTemplateRootToGroup);
var dataTemplate = new DataTemplateSelector<TItem>(TemplateSelector, AddTemplateGroup, AddTemplateRootToGroup);
SetDataTemplateSelectorAction(parent, dataTemplate);
}

Expand All @@ -66,57 +66,58 @@ void INonPhysicalChild.RemoveFromParent(object parentElement) { }
void IContainerElementHandler.AddChild(object child, int physicalSiblingIndex) { }
void IContainerElementHandler.RemoveChild(object child, int physicalSiblingIndex) { }

class DataTemplateSelector : MC.DataTemplateSelector
}

file class DataTemplateSelector<TItem> : MC.DataTemplateSelector
{
private readonly RenderFragment<TItem> _renderFragment;
private readonly Func<int> _addGroupFunc;
private readonly Func<int, MC.View> _addRootToGroupFunc;
private readonly Dictionary<Type, MC.DataTemplate> _dataTemplates = new();

public DataTemplateSelector(RenderFragment<TItem> renderFragment, Func<int> addGroupFunc, Func<int, MC.View> addRootToGroupFunc)
{
private readonly RenderFragment<TItem> _renderFragment;
private readonly Func<int> _addGroupFunc;
private readonly Func<int, MC.View> _addRootToGroupFunc;
private readonly Dictionary<Type, MC.DataTemplate> _dataTemplates = new();
_renderFragment = renderFragment;
_addGroupFunc = addGroupFunc;
_addRootToGroupFunc = addRootToGroupFunc;
}

public DataTemplateSelector(RenderFragment<TItem> renderFragment, Func<int> addGroupFunc, Func<int, MC.View> addRootToGroupFunc)
protected override MC.DataTemplate OnSelectTemplate(object item, MC.BindableObject container)
{
var componentType = GetComponentType(_renderFragment((TItem)item));

if (!_dataTemplates.TryGetValue(componentType, out var dataTemplate))
{
_renderFragment = renderFragment;
_addGroupFunc = addGroupFunc;
_addRootToGroupFunc = addRootToGroupFunc;
var groupIndex = _addGroupFunc();
dataTemplate = new MC.DataTemplate(() => _addRootToGroupFunc(groupIndex));
_dataTemplates[componentType] = dataTemplate;
}

protected override MC.DataTemplate OnSelectTemplate(object item, MC.BindableObject container)
return dataTemplate;
}

static readonly RenderTreeBuilder InspectRenderTreeBuilder = new();
private static Type GetComponentType(RenderFragment renderFragment)
{
// Consider reworking if https://github.com/dotnet/aspnetcore/issues/17200 is implemented.
try
{
var componentType = GetComponentType(_renderFragment((TItem)item));
renderFragment(InspectRenderTreeBuilder);
var frames = InspectRenderTreeBuilder.GetFrames();

if (!_dataTemplates.TryGetValue(componentType, out var dataTemplate))
for (var i = 0; i < frames.Count; i++)
{
var groupIndex = _addGroupFunc();
dataTemplate = new MC.DataTemplate(() => _addRootToGroupFunc(groupIndex));
_dataTemplates[componentType] = dataTemplate;
if (frames.Array[i].FrameType == RenderTreeFrameType.Component)
{
return frames.Array[i].ComponentType;
}
}

return dataTemplate;
throw new InvalidOperationException("RenderFragment does not contain any components.");
}

static readonly RenderTreeBuilder InspectRenderTreeBuilder = new();
private static Type GetComponentType(RenderFragment renderFragment)
finally
{
// Consider reworking if https://github.com/dotnet/aspnetcore/issues/17200 is implemented.
try
{
renderFragment(InspectRenderTreeBuilder);
var frames = InspectRenderTreeBuilder.GetFrames();

for (var i = 0; i < frames.Count; i++)
{
if (frames.Array[i].FrameType == RenderTreeFrameType.Component)
{
return frames.Array[i].ComponentType;
}
}

throw new InvalidOperationException("RenderFragment does not contain any components.");
}
finally
{
InspectRenderTreeBuilder.Clear();
}
InspectRenderTreeBuilder.Clear();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,35 +46,35 @@ public MC.BindableObject AddTemplateRoot(TItem initialItem)
void INonPhysicalChild.SetParent(object parentElement)
{
var parent = (TControl)parentElement;
var dataTemplate = new DataTemplateSelector(AddTemplateRoot);
var dataTemplate = new DataTemplateSelector<TItem>(AddTemplateRoot);
SetDataTemplateAction(parent, dataTemplate);
}

void INonPhysicalChild.RemoveFromParent(object parentElement) { }
object IElementHandler.TargetElement => null;
void IContainerElementHandler.AddChild(object child, int physicalSiblingIndex) { }
void IContainerElementHandler.RemoveChild(object child, int physicalSiblingIndex) { }
}

// In order to be able to render the item synchronously, we need to have an item upfront, before the render.
// Unfortunately, regular DataTemplate does not have an access to the item, it is set set BindingContext afterwards.
// In order to workaround this issue, we use a DataTemplateSelector, which returns the same DataTemplate. But we're able
// to store the item from OnSelectTemplate method, which is used to render the item in DataTemplate.
class DataTemplateSelector : MC.DataTemplateSelector
{
private readonly MC.DataTemplate _dataTemplate;
private readonly Func<TItem, MC.BindableObject> _loadTemplate;
private TItem _initialItem;
// In order to be able to render the item synchronously, we need to have an item upfront, before the render.
// Unfortunately, regular DataTemplate does not have an access to the item, it is set set BindingContext afterwards.
// In order to workaround this issue, we use a DataTemplateSelector, which returns the same DataTemplate. But we're able
// to store the item from OnSelectTemplate method, which is used to render the item in DataTemplate.
file class DataTemplateSelector<TItem> : MC.DataTemplateSelector
{
private readonly MC.DataTemplate _dataTemplate;
private readonly Func<TItem, MC.BindableObject> _loadTemplate;
private TItem _initialItem;

public DataTemplateSelector(Func<TItem, MC.BindableObject> loadTemplate)
{
_loadTemplate = loadTemplate;
_dataTemplate = new MC.DataTemplate(() => _loadTemplate(_initialItem));
}
public DataTemplateSelector(Func<TItem, MC.BindableObject> loadTemplate)
{
_loadTemplate = loadTemplate;
_dataTemplate = new MC.DataTemplate(() => _loadTemplate(_initialItem));
}

protected override MC.DataTemplate OnSelectTemplate(object item, MC.BindableObject container)
{
_initialItem = (TItem)item;
return _dataTemplate;
}
protected override MC.DataTemplate OnSelectTemplate(object item, MC.BindableObject container)
{
_initialItem = (TItem)item;
return _dataTemplate;
}
}
}

0 comments on commit d1a26a1

Please sign in to comment.