Add support for frame range frame types
This enables supporting nested components
This commit is contained in:
Родитель
79ede4e1d0
Коммит
6a29678b7e
|
@ -54,7 +54,7 @@ namespace BlinForms.Framework
|
|||
foreach (var updatedComponent in renderBatch.UpdatedComponents.Array.Take(renderBatch.UpdatedComponents.Count))
|
||||
{
|
||||
var adapter = _componentIdToAdapter[updatedComponent.ComponentId];
|
||||
adapter.ApplyEdits(updatedComponent.Edits, renderBatch.ReferenceFrames);
|
||||
adapter.ApplyEdits(updatedComponent.ComponentId, updatedComponent.Edits, renderBatch.ReferenceFrames, renderBatch);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using BlinForms.Framework.Controls;
|
||||
using Microsoft.AspNetCore.Components.Rendering;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -37,14 +38,14 @@ namespace BlinForms.Framework
|
|||
return $"Blontrol: Name={Name ?? "<?>"}, Target={TargetControl?.GetType().Name ?? "<?>"}, #Children={Children.Count}";
|
||||
}
|
||||
|
||||
internal void ApplyEdits(ArrayBuilderSegment<RenderTreeEdit> edits, ArrayRange<RenderTreeFrame> referenceFrames)
|
||||
internal void ApplyEdits(int componentId, ArrayBuilderSegment<RenderTreeEdit> edits, ArrayRange<RenderTreeFrame> referenceFrames, RenderBatch batch)
|
||||
{
|
||||
foreach (var edit in edits)
|
||||
{
|
||||
switch (edit.Type)
|
||||
{
|
||||
case RenderTreeEditType.PrependFrame:
|
||||
ApplyPrependFrame(edit.SiblingIndex, referenceFrames.Array, edit.ReferenceFrameIndex);
|
||||
ApplyPrependFrame(batch, componentId, edit.SiblingIndex, referenceFrames.Array, edit.ReferenceFrameIndex);
|
||||
break;
|
||||
case RenderTreeEditType.SetAttribute:
|
||||
ApplySetAttribute(edit.SiblingIndex, ref referenceFrames.Array[edit.ReferenceFrameIndex]);
|
||||
|
@ -78,15 +79,15 @@ namespace BlinForms.Framework
|
|||
mapper.SetControlProperty(attributeFrame.AttributeEventHandlerId, attributeFrame.AttributeName, attributeFrame.AttributeValue, attributeFrame.AttributeEventUpdatesAttributeName);
|
||||
}
|
||||
|
||||
private void ApplyPrependFrame(int siblingIndex, RenderTreeFrame[] frames, int frameIndex)
|
||||
private int ApplyPrependFrame(RenderBatch batch, int componentId, int siblingIndex, RenderTreeFrame[] frames, int frameIndex)
|
||||
{
|
||||
ref var frame = ref frames[frameIndex];
|
||||
switch (frame.FrameType)
|
||||
{
|
||||
case RenderTreeFrameType.Element:
|
||||
{
|
||||
InsertElement(siblingIndex, frames, frameIndex);
|
||||
break;
|
||||
InsertElement(siblingIndex, frames, frameIndex, componentId, batch);
|
||||
return 1;
|
||||
}
|
||||
case RenderTreeFrameType.Component:
|
||||
{
|
||||
|
@ -94,7 +95,11 @@ namespace BlinForms.Framework
|
|||
var childAdapter = Renderer.CreateAdapterForChildComponent(frame.ComponentId);
|
||||
childAdapter.Name = $"For: '{frame.Component.GetType().FullName}'";
|
||||
AddChildAdapter(siblingIndex, childAdapter);
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
case RenderTreeFrameType.Region:
|
||||
{
|
||||
return InsertFrameRange(batch, componentId, siblingIndex, frames, frameIndex + 1, frameIndex + frame.RegionSubtreeLength);
|
||||
}
|
||||
case RenderTreeFrameType.Markup:
|
||||
{
|
||||
|
@ -103,7 +108,7 @@ namespace BlinForms.Framework
|
|||
throw new NotImplementedException("Nonempty markup: " + frame.MarkupContent);
|
||||
}
|
||||
Children.Add(new BlontrolAdapter(Renderer) { Name = $"Dummy markup, sib#={siblingIndex}" });
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
case RenderTreeFrameType.Text:
|
||||
{
|
||||
|
@ -113,24 +118,31 @@ namespace BlinForms.Framework
|
|||
throw new NotImplementedException("Nonempty text: " + frame.TextContent);
|
||||
}
|
||||
Children.Add(new BlontrolAdapter(Renderer) { Name = $"Dummy text, sib#={siblingIndex}" });
|
||||
break;
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException($"Not supported frame type: {frame.FrameType}");
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertElement(int siblingIndex, RenderTreeFrame[] frames, int frameIndex)
|
||||
private void InsertElement(int siblingIndex, RenderTreeFrame[] frames, int frameIndex, int componentId, RenderBatch batch)
|
||||
{
|
||||
// Elements represent Winforms native controls
|
||||
ref var frame = ref frames[frameIndex];
|
||||
var elementName = frame.ElementName;
|
||||
var nativeControl = KnownElements[elementName](Renderer);
|
||||
|
||||
TargetControl = nativeControl;
|
||||
|
||||
// Add the new native control to the parent's child controls (the parent adapter is our
|
||||
// container, so the parent adapter's control is our control's container.
|
||||
AddChildControl(siblingIndex, TargetControl);
|
||||
|
||||
|
||||
var endIndexExcl = frameIndex + frames[frameIndex].ElementSubtreeLength;
|
||||
for (var attributeIndex = frameIndex + 1; attributeIndex < endIndexExcl; attributeIndex++)
|
||||
for (var descendantIndex = frameIndex + 1; descendantIndex < endIndexExcl; descendantIndex++)
|
||||
{
|
||||
var candidateFrame = frames[attributeIndex];
|
||||
var candidateFrame = frames[descendantIndex];
|
||||
if (candidateFrame.FrameType == RenderTreeFrameType.Attribute)
|
||||
{
|
||||
// TODO: Do smarter property setting...? Not calling <NativeControl>.ApplyAttribute(...) right now. Should it?
|
||||
|
@ -139,16 +151,13 @@ namespace BlinForms.Framework
|
|||
}
|
||||
else
|
||||
{
|
||||
// TODO: Do recursive thing
|
||||
// As soon as we see a non-attribute child, all the subsequent child frames are
|
||||
// not attributes, so bail out and insert the remnants recursively
|
||||
InsertFrameRange(batch, componentId, childIndex: 0, frames, descendantIndex, endIndexExcl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TargetControl = nativeControl;
|
||||
|
||||
// Add the new native control to the parent's child controls (the parent adapter is our
|
||||
// container, so the parent adapter's control is our control's container.
|
||||
AddChildControl(siblingIndex, TargetControl);
|
||||
|
||||
//// Ignoring non-controls, such as Timer Component
|
||||
|
||||
|
@ -162,6 +171,36 @@ namespace BlinForms.Framework
|
|||
//}
|
||||
}
|
||||
|
||||
private int InsertFrameRange(RenderBatch batch, int componentId, int childIndex, RenderTreeFrame[] frames, int startIndex, int endIndexExcl)
|
||||
{
|
||||
var origChildIndex = childIndex;
|
||||
for (var index = startIndex; index < endIndexExcl; index++)
|
||||
{
|
||||
ref var frame = ref batch.ReferenceFrames.Array[index];
|
||||
var numChildrenInserted = ApplyPrependFrame(batch, componentId, childIndex, frames, index);
|
||||
childIndex += numChildrenInserted;
|
||||
|
||||
// Skip over any descendants, since they are already dealt with recursively
|
||||
index += CountDescendantFrames(frame);
|
||||
}
|
||||
|
||||
return (childIndex - origChildIndex); // Total number of children inserted
|
||||
}
|
||||
|
||||
private int CountDescendantFrames(RenderTreeFrame frame)
|
||||
{
|
||||
return frame.FrameType switch
|
||||
{
|
||||
// The following frame types have a subtree length. Other frames may use that memory slot
|
||||
// to mean something else, so we must not read it. We should consider having nominal subtypes
|
||||
// of RenderTreeFramePointer that prevent access to non-applicable fields.
|
||||
RenderTreeFrameType.Component => frame.ComponentSubtreeLength - 1,
|
||||
RenderTreeFrameType.Element => frame.ElementSubtreeLength - 1,
|
||||
RenderTreeFrameType.Region => frame.RegionSubtreeLength - 1,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
||||
private void AddChildAdapter(int siblingIndex, BlontrolAdapter childAdapter)
|
||||
{
|
||||
childAdapter.Parent = this;
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
@using BlinForms.Framework.Controls
|
||||
@using System.Drawing
|
||||
|
||||
<Button Top="50" Width="300" Text="@("Increment: " + count)" Height="20" OnClick="@IncrementCount" />
|
||||
|
||||
<Panel Visible="true" BackColor="Color.Red" Top="300" Left="300" Width="300" Height="50">
|
||||
<Panel Visible="true" BackColor="Color.Red" Top="300" Left="300" Width="300" Height="100">
|
||||
<Label Top="50" Left="10" Width="150" Height="23" BackColor="Color.Yellow" Text="This label is nested"></Label>
|
||||
</Panel>
|
||||
|
||||
<Label Top="100" Width="200" Height="20" Text="@("I'm a label: " + labelCount)"></Label>
|
||||
|
||||
@*<Timer OnTick="@OnTimerTick" />*@
|
||||
|
||||
<Button Top="200" Width="400" Height="20" Text="@($"Show details... (visible={isDetailsVisible})")" OnClick="@ToggleDetailsVisible" />
|
||||
<Button Top="50" Width="300" Text="@("Increment: " + count)" Height="23" OnClick="@IncrementCount" />
|
||||
|
||||
<Label Top="100" Width="200" Height="23" BackColor="Color.AliceBlue" Text="@("I'm a label: " + labelCount)"></Label>
|
||||
|
||||
|
||||
<Button Top="200" Width="400" Height="23" BackColor="Color.Orange" Text="@($"Show details... (visible={isDetailsVisible})")" OnClick="@ToggleDetailsVisible" />
|
||||
|
||||
@if (isDetailsVisible)
|
||||
{
|
||||
<Label Top="250" Width="200" Height="20" Text="Details visible.."></Label>
|
||||
<Label Top="250" Width="200" Height="23" BackColor="Color.Cyan" Text="Details visible.."></Label>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Label Top="300" Width="200" Height="20" Text="Details NOT visible..."></Label>
|
||||
<Label Top="300" Width="200" Height="23" BackColor="Color.Magenta" Text="Details NOT visible..."></Label>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
|
Загрузка…
Ссылка в новой задаче