Introduction of BlontrolAdapters
- Removed container Blontrols and replaced with shadow tree of BlontrolAdapters - Temporarily removed Timer component (it's not a Control, so it's tricky)
This commit is contained in:
Родитель
03a07eb7b1
Коммит
aa14c286a5
|
@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Components.Rendering;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
@ -12,7 +11,7 @@ namespace BlinForms.Framework
|
|||
{
|
||||
public class BlinFormsRenderer : Renderer
|
||||
{
|
||||
private Dictionary<int, Blontrol> _componentIdToControl = new Dictionary<int, Blontrol>(); // TODO: Map to Control
|
||||
private Dictionary<int, BlontrolAdapter> _componentIdToAdapter = new Dictionary<int, BlontrolAdapter>();
|
||||
|
||||
public BlinFormsRenderer(IServiceProvider serviceProvider)
|
||||
: base(serviceProvider, new LoggerFactory())
|
||||
|
@ -28,12 +27,20 @@ namespace BlinForms.Framework
|
|||
{
|
||||
var component = InstantiateComponent(typeof(T));
|
||||
var componentId = AssignRootComponentId(component);
|
||||
var control = _componentIdToControl[componentId] =
|
||||
new Blontrol(this)
|
||||
var adapter = _componentIdToAdapter[componentId] =
|
||||
new BlontrolAdapter(this)
|
||||
{
|
||||
Size = new Size(500, 500),
|
||||
Name = "Root BlontrolAdapter",
|
||||
// TODO: Might actually want to keep this dummy control so that Blinforms can be an island in a form. But, need
|
||||
// to figure out its default size etc. Perhaps top-level Razor class implements ITopLevel{FormSettings} interface
|
||||
// to control 'container Form' options?
|
||||
TargetControl = new Control()
|
||||
{
|
||||
Width = 500,
|
||||
Height = 500,
|
||||
},
|
||||
};
|
||||
RootForm.Controls.Add(control);
|
||||
RootForm.Controls.Add(adapter.TargetControl);
|
||||
return RenderRootComponentAsync(componentId);
|
||||
}
|
||||
|
||||
|
@ -46,17 +53,17 @@ namespace BlinForms.Framework
|
|||
{
|
||||
foreach (var updatedComponent in renderBatch.UpdatedComponents.Array.Take(renderBatch.UpdatedComponents.Count))
|
||||
{
|
||||
var control = _componentIdToControl[updatedComponent.ComponentId];
|
||||
control.ApplyEdits(updatedComponent.Edits, renderBatch.ReferenceFrames);
|
||||
var adapter = _componentIdToAdapter[updatedComponent.ComponentId];
|
||||
adapter.ApplyEdits(updatedComponent.Edits, renderBatch.ReferenceFrames);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
internal Blontrol CreateControlForChildComponent(int componentId)
|
||||
internal BlontrolAdapter CreateAdapterForChildComponent(int componentId)
|
||||
{
|
||||
var result = new Blontrol(this);
|
||||
_componentIdToControl[componentId] = result;
|
||||
var result = new BlontrolAdapter(this);
|
||||
_componentIdToAdapter[componentId] = result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
using BlinForms.Framework.Controls;
|
||||
using BlinForms.Framework.Elements;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
|
||||
namespace BlinForms.Framework
|
||||
{
|
||||
public class Blontrol : Control
|
||||
{
|
||||
private readonly BlinFormsRenderer _renderer;
|
||||
private readonly List<Control> _childControls = new List<Control>();
|
||||
|
||||
internal static Dictionary<string, Func<BlinFormsRenderer, IBlazorNativeControl>> KnownElements { get; }
|
||||
= new Dictionary<string, Func<BlinFormsRenderer, IBlazorNativeControl>>();
|
||||
|
||||
public Blontrol(BlinFormsRenderer renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
}
|
||||
|
||||
internal void ApplyEdits(ArrayBuilderSegment<RenderTreeEdit> edits, ArrayRange<RenderTreeFrame> referenceFrames)
|
||||
{
|
||||
foreach (var edit in edits)
|
||||
{
|
||||
switch (edit.Type)
|
||||
{
|
||||
case RenderTreeEditType.PrependFrame:
|
||||
ApplyPrependFrame(edit.SiblingIndex, referenceFrames.Array, edit.ReferenceFrameIndex);
|
||||
break;
|
||||
case RenderTreeEditType.SetAttribute:
|
||||
ApplySetAttribute(edit.SiblingIndex, ref referenceFrames.Array[edit.ReferenceFrameIndex]);
|
||||
break;
|
||||
case RenderTreeEditType.RemoveFrame:
|
||||
ApplyRemoveFrame(edit.SiblingIndex);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"Not supported edit type: {edit.Type}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyRemoveFrame(int siblingIndex)
|
||||
{
|
||||
//Controls.RemoveAt(siblingIndex);
|
||||
}
|
||||
|
||||
private void ApplySetAttribute(int siblingIndex, ref RenderTreeFrame attributeFrame)
|
||||
{
|
||||
var target = (IBlazorNativeControl)Controls[siblingIndex];
|
||||
target.ApplyAttribute(ref attributeFrame);
|
||||
}
|
||||
|
||||
private void ApplyPrependFrame(int siblingIndex, RenderTreeFrame[] frames, int frameIndex)
|
||||
{
|
||||
ref var frame = ref frames[frameIndex];
|
||||
switch (frame.FrameType)
|
||||
{
|
||||
case RenderTreeFrameType.Element: // ... then this gets called to create the native component
|
||||
var element = CreateNativeControlForElement(frames, frameIndex);
|
||||
|
||||
// Ignoring non-controls, such as Timer Component
|
||||
|
||||
if (element is Control elementControl)
|
||||
{
|
||||
AddChildControl(siblingIndex, elementControl);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("Ignoring non-control child: " + element.GetType().FullName);
|
||||
}
|
||||
break;
|
||||
case RenderTreeFrameType.Component: // ... first a bunch of these get created for each "thing"
|
||||
{
|
||||
var childControl = _renderer.CreateControlForChildComponent(frame.ComponentId);
|
||||
AddChildControl(siblingIndex, childControl);
|
||||
break;
|
||||
}
|
||||
case RenderTreeFrameType.Markup:
|
||||
if (!string.IsNullOrWhiteSpace(frame.MarkupContent))
|
||||
{
|
||||
throw new NotImplementedException("Nonempty markup: " + frame.MarkupContent);
|
||||
}
|
||||
break;
|
||||
case RenderTreeFrameType.Text:
|
||||
if (!string.IsNullOrWhiteSpace(frame.TextContent))
|
||||
{
|
||||
throw new NotImplementedException("Nonempty text: " + frame.TextContent);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"Not supported frame type: {frame.FrameType}");
|
||||
}
|
||||
}
|
||||
|
||||
private void AddChildControl(int siblingIndex, Control childControl)
|
||||
{
|
||||
Controls.Add(childControl);
|
||||
|
||||
// TODO: _childControls is never read from... only added to...
|
||||
if (siblingIndex < _childControls.Count)
|
||||
{
|
||||
_childControls.Insert(siblingIndex, childControl);
|
||||
}
|
||||
else
|
||||
{
|
||||
_childControls.Add(childControl);
|
||||
}
|
||||
}
|
||||
|
||||
private IBlazorNativeControl CreateNativeControlForElement(RenderTreeFrame[] frames, int frameIndex)
|
||||
{
|
||||
ref var frame = ref frames[frameIndex];
|
||||
var elementName = frame.ElementName;
|
||||
var nativeControl = KnownElements[elementName](_renderer);
|
||||
|
||||
foreach (var attribute in AttributeUtil.ElementAttributeFrames(frames, frameIndex))
|
||||
{
|
||||
var attributeCopy = attribute;
|
||||
nativeControl.ApplyAttribute(ref attributeCopy);
|
||||
}
|
||||
|
||||
return nativeControl;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
using BlinForms.Framework.Elements;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BlinForms.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a "shadow" item that Blazor uses to map changes into the live WinForms control tree.
|
||||
/// </summary>
|
||||
public class BlontrolAdapter
|
||||
{
|
||||
internal static Dictionary<string, Func<BlinFormsRenderer, Control>> KnownElements { get; }
|
||||
= new Dictionary<string, Func<BlinFormsRenderer, Control>>();
|
||||
|
||||
public BlontrolAdapter(BlinFormsRenderer renderer)
|
||||
{
|
||||
Renderer = renderer ?? throw new ArgumentNullException(nameof(renderer));
|
||||
}
|
||||
|
||||
public BlontrolAdapter Parent { get; set; }
|
||||
public List<BlontrolAdapter> Children { get; } = new List<BlontrolAdapter>();
|
||||
|
||||
// TODO: Is this the right concept? A component might have multiple WinForms controls created?
|
||||
public Control TargetControl { get; set; }
|
||||
|
||||
public BlinFormsRenderer Renderer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Used for debugging purposes.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Blontrol: Name={Name ?? "<?>"}, Target={TargetControl?.GetType().Name ?? "<?>"}, #Children={Children.Count}";
|
||||
}
|
||||
|
||||
internal void ApplyEdits(ArrayBuilderSegment<RenderTreeEdit> edits, ArrayRange<RenderTreeFrame> referenceFrames)
|
||||
{
|
||||
foreach (var edit in edits)
|
||||
{
|
||||
switch (edit.Type)
|
||||
{
|
||||
case RenderTreeEditType.PrependFrame:
|
||||
ApplyPrependFrame(edit.SiblingIndex, referenceFrames.Array, edit.ReferenceFrameIndex);
|
||||
break;
|
||||
case RenderTreeEditType.SetAttribute:
|
||||
ApplySetAttribute(edit.SiblingIndex, ref referenceFrames.Array[edit.ReferenceFrameIndex]);
|
||||
break;
|
||||
case RenderTreeEditType.RemoveFrame:
|
||||
ApplyRemoveFrame(edit.SiblingIndex);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException($"Not supported edit type: {edit.Type}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyRemoveFrame(int siblingIndex)
|
||||
{
|
||||
//Controls.RemoveAt(siblingIndex);
|
||||
}
|
||||
|
||||
private void ApplySetAttribute(int siblingIndex, ref RenderTreeFrame attributeFrame)
|
||||
{
|
||||
//var target = (IBlazorNativeControl)Controls[siblingIndex];
|
||||
//target.ApplyAttribute(ref attributeFrame);
|
||||
}
|
||||
|
||||
private void ApplyPrependFrame(int siblingIndex, RenderTreeFrame[] frames, int frameIndex)
|
||||
{
|
||||
ref var frame = ref frames[frameIndex];
|
||||
switch (frame.FrameType)
|
||||
{
|
||||
case RenderTreeFrameType.Element:
|
||||
{
|
||||
// Elements represent Winforms native controls
|
||||
var element = CreateNativeControlForElement(frames, frameIndex);
|
||||
TargetControl = element;
|
||||
|
||||
// Add the new nataive control to the parent's child controls (the parent adapter is our
|
||||
// container, so the parent adapter's control is our control's container.
|
||||
// TODO: What about siblingIndex?
|
||||
Parent.TargetControl.Controls.Add(TargetControl);
|
||||
|
||||
//// Ignoring non-controls, such as Timer Component
|
||||
|
||||
//if (element is Control elementControl)
|
||||
//{
|
||||
// AddChildControl(siblingIndex, elementControl);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// Debug.WriteLine("Ignoring non-control child: " + element.GetType().FullName);
|
||||
//}
|
||||
break;
|
||||
}
|
||||
case RenderTreeFrameType.Component:
|
||||
{
|
||||
// Components are represented by BlontrolAdapters
|
||||
var childAdapter = Renderer.CreateAdapterForChildComponent(frame.ComponentId);
|
||||
childAdapter.Name = $"For: '{frame.Component.GetType().FullName}'";
|
||||
AddChildAdapter(siblingIndex, childAdapter);
|
||||
break;
|
||||
}
|
||||
case RenderTreeFrameType.Markup:
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(frame.MarkupContent))
|
||||
{
|
||||
throw new NotImplementedException("Nonempty markup: " + frame.MarkupContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RenderTreeFrameType.Text:
|
||||
{
|
||||
// TODO: Maybe support this for Labels for Text property, etc. ("DefaultProperty"?)
|
||||
if (!string.IsNullOrWhiteSpace(frame.TextContent))
|
||||
{
|
||||
throw new NotImplementedException("Nonempty text: " + frame.TextContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException($"Not supported frame type: {frame.FrameType}");
|
||||
}
|
||||
}
|
||||
|
||||
private Control CreateNativeControlForElement(RenderTreeFrame[] frames, int frameIndex)
|
||||
{
|
||||
ref var frame = ref frames[frameIndex];
|
||||
var elementName = frame.ElementName;
|
||||
var nativeControl = KnownElements[elementName](Renderer);
|
||||
|
||||
foreach (var attribute in AttributeUtil.ElementAttributeFrames(frames, frameIndex))
|
||||
{
|
||||
// TODO: Do smarter property setting...? Not calling <NativeControl>.ApplyAttribute(...) right now. Should it?
|
||||
var attributeCopy = attribute;
|
||||
var mapper = GetControlPropertyMapper(nativeControl);
|
||||
mapper.SetControlProperty(attributeCopy.AttributeEventHandlerId, attributeCopy.AttributeName, attributeCopy.AttributeValue, attributeCopy.AttributeEventUpdatesAttributeName);
|
||||
}
|
||||
|
||||
return nativeControl;
|
||||
}
|
||||
|
||||
private void AddChildAdapter(int siblingIndex, BlontrolAdapter childAdapter)
|
||||
{
|
||||
childAdapter.Parent = this;
|
||||
|
||||
if (siblingIndex < Children.Count)
|
||||
{
|
||||
Children.Insert(siblingIndex, childAdapter);
|
||||
}
|
||||
else
|
||||
{
|
||||
Children.Add(childAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
private static IControlPropertyMapper GetControlPropertyMapper(Control control)
|
||||
{
|
||||
// TODO: Have control-specific ones, but also need a general one for custom controls? Or maybe not needed?
|
||||
return new ReflectionControlPropertyMapper(control);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
|
||||
namespace BlinForms.Framework.Controls
|
||||
|
@ -9,7 +7,7 @@ namespace BlinForms.Framework.Controls
|
|||
{
|
||||
static Button()
|
||||
{
|
||||
Blontrol.KnownElements.Add(typeof(Button).FullName, renderer => new BlazorButton(renderer));
|
||||
BlontrolAdapter.KnownElements.Add(typeof(Button).FullName, renderer => new BlazorButton(renderer));
|
||||
}
|
||||
|
||||
[Parameter] public string Text { get; set; }
|
||||
|
@ -36,30 +34,6 @@ namespace BlinForms.Framework.Controls
|
|||
};
|
||||
}
|
||||
|
||||
protected override void OnParentChanged(EventArgs e)
|
||||
{
|
||||
base.OnParentChanged(e);
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
Parent.Location = Location;
|
||||
Location = Point.Empty;
|
||||
Parent.Size = Size;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSizeChanged(EventArgs e)
|
||||
{
|
||||
base.OnSizeChanged(e);
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
Parent.Location = Location;
|
||||
Location = Point.Empty;
|
||||
Parent.Size = Size;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyAttribute(ref RenderTreeFrame attribute)
|
||||
{
|
||||
switch (attribute.AttributeName)
|
||||
|
|
|
@ -20,15 +20,21 @@ namespace BlinForms.Framework.Controls
|
|||
builder.AddAttribute(200, nameof(Left), Left);
|
||||
builder.AddAttribute(300, nameof(Width), Width);
|
||||
builder.AddAttribute(400, nameof(Height), Height);
|
||||
RenderContents(builder);
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
protected abstract void RenderAttributes(RenderTreeBuilder builder);
|
||||
|
||||
protected virtual void RenderContents(RenderTreeBuilder builder)
|
||||
{
|
||||
}
|
||||
|
||||
public static void ApplyAttribute(Control control, ref RenderTreeFrame attributeFrame)
|
||||
{
|
||||
switch (attributeFrame.AttributeName)
|
||||
{
|
||||
// TODO: Fix not setting default values for types. Maybe use nullable types on components?
|
||||
case nameof(Top):
|
||||
if ((attributeFrame.AttributeValue as string) != "0")
|
||||
control.Top = int.Parse((string)attributeFrame.AttributeValue);
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace BlinForms.Framework.Controls
|
||||
{
|
||||
|
@ -9,7 +7,7 @@ namespace BlinForms.Framework.Controls
|
|||
{
|
||||
static Label()
|
||||
{
|
||||
Blontrol.KnownElements.Add(typeof(Label).FullName, renderer => new BlazorLabel());
|
||||
BlontrolAdapter.KnownElements.Add(typeof(Label).FullName, renderer => new BlazorLabel());
|
||||
}
|
||||
|
||||
[Parameter] public string Text { get; set; }
|
||||
|
@ -25,30 +23,6 @@ namespace BlinForms.Framework.Controls
|
|||
{
|
||||
}
|
||||
|
||||
protected override void OnParentChanged(EventArgs e)
|
||||
{
|
||||
base.OnParentChanged(e);
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
Parent.Location = Location;
|
||||
Location = Point.Empty;
|
||||
Parent.Size = Size;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSizeChanged(EventArgs e)
|
||||
{
|
||||
base.OnSizeChanged(e);
|
||||
|
||||
if (Parent != null)
|
||||
{
|
||||
Parent.Location = Location;
|
||||
Location = Point.Empty;
|
||||
Parent.Size = Size;
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyAttribute(ref RenderTreeFrame attribute)
|
||||
{
|
||||
switch (attribute.AttributeName)
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
using System.Drawing;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.RenderTree;
|
||||
|
||||
namespace BlinForms.Framework.Controls
|
||||
{
|
||||
public class Panel : FormsComponentBase
|
||||
{
|
||||
static Panel()
|
||||
{
|
||||
BlontrolAdapter.KnownElements.Add(typeof(Panel).FullName, renderer => new BlazorPanel(renderer));
|
||||
}
|
||||
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public bool Visible { get; set; }
|
||||
[Parameter] public Color BackColor { get; set; }
|
||||
|
||||
protected override void RenderAttributes(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.AddAttribute(1, nameof(Visible), Visible);
|
||||
builder.AddAttribute(2, nameof(BackColor), BackColor.ToArgb());
|
||||
}
|
||||
|
||||
protected override void RenderContents(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.AddContent(999999, ChildContent);
|
||||
}
|
||||
|
||||
class BlazorPanel : System.Windows.Forms.Panel, IBlazorNativeControl
|
||||
{
|
||||
public BlazorPanel(BlinFormsRenderer renderer)
|
||||
{
|
||||
}
|
||||
|
||||
public void ApplyAttribute(ref RenderTreeFrame attribute)
|
||||
{
|
||||
switch (attribute.AttributeName)
|
||||
{
|
||||
case nameof(Visible):
|
||||
Visible = (bool)attribute.AttributeValue;
|
||||
break;
|
||||
case nameof(BackColor):
|
||||
BackColor = Color.FromArgb(argb: (int)attribute.AttributeValue);
|
||||
break;
|
||||
//case "onclick":
|
||||
// ClickEventHandlerId = attribute.AttributeEventHandlerId;
|
||||
// break;
|
||||
default:
|
||||
FormsComponentBase.ApplyAttribute(this, ref attribute);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,49 +4,49 @@ using System.Windows.Forms;
|
|||
|
||||
namespace BlinForms.Framework.Controls
|
||||
{
|
||||
public class Timer : FormsComponentBase
|
||||
{
|
||||
static Timer()
|
||||
{
|
||||
Blontrol.KnownElements.Add(typeof(Timer).FullName, renderer => new BlazorTimer(renderer));
|
||||
}
|
||||
//public class Timer : FormsComponentBase
|
||||
//{
|
||||
// static Timer()
|
||||
// {
|
||||
// BlontrolAdapter.KnownElements.Add(typeof(Timer).FullName, renderer => new BlazorTimer(renderer));
|
||||
// }
|
||||
|
||||
[Parameter] public EventCallback OnTick { get; set; }
|
||||
// [Parameter] public EventCallback OnTick { get; set; }
|
||||
|
||||
protected override void RenderAttributes(RenderTreeBuilder builder)
|
||||
{
|
||||
builder.AddAttribute(1, "ontick", OnTick);
|
||||
}
|
||||
// protected override void RenderAttributes(RenderTreeBuilder builder)
|
||||
// {
|
||||
// builder.AddAttribute(1, "ontick", OnTick);
|
||||
// }
|
||||
|
||||
class BlazorTimer : System.Windows.Forms.Timer, IBlazorNativeControl
|
||||
{
|
||||
public ulong TickEventHandlerId { get; set; }
|
||||
// class BlazorTimer : System.Windows.Forms.Timer, IBlazorNativeControl
|
||||
// {
|
||||
// public ulong TickEventHandlerId { get; set; }
|
||||
|
||||
public BlazorTimer(BlinFormsRenderer renderer)
|
||||
{
|
||||
Interval = 1000;
|
||||
Tick += (s, e) =>
|
||||
{
|
||||
if (TickEventHandlerId != default)
|
||||
{
|
||||
renderer.DispatchEventAsync(TickEventHandlerId, null, new UIEventArgs());
|
||||
}
|
||||
};
|
||||
Enabled = true;
|
||||
}
|
||||
// public BlazorTimer(BlinFormsRenderer renderer)
|
||||
// {
|
||||
// Interval = 1000;
|
||||
// Tick += (s, e) =>
|
||||
// {
|
||||
// if (TickEventHandlerId != default)
|
||||
// {
|
||||
// renderer.DispatchEventAsync(TickEventHandlerId, null, new UIEventArgs());
|
||||
// }
|
||||
// };
|
||||
// Enabled = true;
|
||||
// }
|
||||
|
||||
public void ApplyAttribute(ref RenderTreeFrame attribute)
|
||||
{
|
||||
switch (attribute.AttributeName)
|
||||
{
|
||||
case "ontick":
|
||||
TickEventHandlerId = attribute.AttributeEventHandlerId;
|
||||
break;
|
||||
default:
|
||||
//FormsComponentBase.ApplyAttribute(this, ref attribute);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// public void ApplyAttribute(ref RenderTreeFrame attribute)
|
||||
// {
|
||||
// switch (attribute.AttributeName)
|
||||
// {
|
||||
// case "ontick":
|
||||
// TickEventHandlerId = attribute.AttributeEventHandlerId;
|
||||
// break;
|
||||
// default:
|
||||
// //FormsComponentBase.ApplyAttribute(this, ref attribute);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
namespace BlinForms.Framework
|
||||
{
|
||||
internal interface IControlPropertyMapper
|
||||
{
|
||||
void SetControlProperty(ulong attributeEventHandlerId,
|
||||
string attributeName,
|
||||
object attributeValue,
|
||||
string attributeEventUpdatesAttributeName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System.Diagnostics;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BlinForms.Framework
|
||||
{
|
||||
internal class ReflectionControlPropertyMapper : IControlPropertyMapper
|
||||
{
|
||||
private readonly Control _control;
|
||||
|
||||
public ReflectionControlPropertyMapper(Control control)
|
||||
{
|
||||
_control = control;
|
||||
}
|
||||
|
||||
public void SetControlProperty(ulong attributeEventHandlerId, string attributeName, object attributeValue, string attributeEventUpdatesAttributeName)
|
||||
{
|
||||
// TODO: Figure out how to wire up events, e.g. OnClick
|
||||
var propertyInfo = _control.GetType().GetProperty(attributeName);
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
if (propertyInfo.PropertyType == typeof(string))
|
||||
{
|
||||
propertyInfo.SetValue(_control, attributeValue);
|
||||
}
|
||||
else if (propertyInfo.PropertyType == typeof(int))
|
||||
{
|
||||
propertyInfo.SetValue(_control, int.Parse((string)attributeValue));
|
||||
}
|
||||
else if (propertyInfo.PropertyType == typeof(bool))
|
||||
{
|
||||
propertyInfo.SetValue(_control, attributeValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine($"Unknown property type '{propertyInfo.PropertyType}' for '{attributeName}' on '{_control.GetType().FullName}'.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine($"Unknown property '{attributeName}' on '{_control.GetType().FullName}'. Maybe an event handler?");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +1,23 @@
|
|||
@using BlinForms.Framework.Controls
|
||||
@using System.Drawing
|
||||
|
||||
<Button Top="50" Width="300" Text="@("Increment: " + count)" OnClick="@IncrementCount" />
|
||||
<Button Top="50" Width="300" Text="@("Increment: " + count)" Height="20" OnClick="@IncrementCount" />
|
||||
|
||||
<Label Top="100" Width="200" Text="@("I'm a label: " + labelCount)"></Label>
|
||||
<Timer OnTick="@OnTimerTick" />
|
||||
<Panel Visible="true" BackColor="Color.Red" Top="300" Left="300" Width="300" Height="50">
|
||||
</Panel>
|
||||
|
||||
<Button Top="200" Width="400" Text="@($"Toggle visible (visible={isDetailsVisible})")" OnClick="@ToggleVisible" />
|
||||
<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="@($"Toggle visible (visible={isDetailsVisible})")" OnClick="@ToggleVisible" />
|
||||
|
||||
@if (isDetailsVisible)
|
||||
{
|
||||
<Label Top="250" Width="200" Text="I am visible!"></Label>
|
||||
<Label Top="250" Width="200" Height="20" Text="I am visible!"></Label>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Label Top="300" Width="200" Text="Not visible..."></Label>
|
||||
<Label Top="300" Width="200" Height="20" Text="Not visible..."></Label>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
|
Загрузка…
Ссылка в новой задаче