Implement VisualElementRenderers

This commit is contained in:
Frank A. Krueger 2017-11-09 01:38:19 -08:00
parent 3d148e7e9f
commit a828fb9b0b
16 changed files with 380 additions and 60 deletions

View File

@ -0,0 +1,26 @@
using System;
using Xamarin.Forms;
namespace Ooui.Forms
{
public class VisualElementChangedEventArgs : ElementChangedEventArgs<VisualElement>
{
public VisualElementChangedEventArgs (VisualElement oldElement, VisualElement newElement)
: base (oldElement, newElement)
{
}
}
public class ElementChangedEventArgs<TElement> : EventArgs where TElement : Xamarin.Forms.Element
{
public ElementChangedEventArgs (TElement oldElement, TElement newElement)
{
OldElement = oldElement;
NewElement = newElement;
}
public TElement NewElement { get; private set; }
public TElement OldElement { get; private set; }
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace Ooui.Forms.Extensions
{
public static class ColorExtensions
{
public static Color ToOouiColor (this Xamarin.Forms.Color color)
{
return new Color ((byte)(color.R * 255.0 + 0.5), (byte)(color.G * 255.0 + 0.5), (byte)(color.B * 255.0 + 0.5), (byte)(color.A * 255.0 + 0.5));
}
}
}

View File

@ -7,6 +7,7 @@ using System.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Ooui;
namespace Xamarin.Forms
{
@ -33,6 +34,13 @@ namespace Xamarin.Forms
});
}
public static event EventHandler<ViewInitializedEventArgs> ViewInitialized;
public static void SendViewInitialized (this VisualElement self, Ooui.Element nativeView)
{
ViewInitialized?.Invoke (self, new ViewInitializedEventArgs { View = self, NativeView = nativeView });
}
class OouiDeviceInfo : DeviceInfo
{
public override Size PixelScreenSize => new Size (640, 480);
@ -93,5 +101,11 @@ namespace Xamarin.Forms
throw new NotImplementedException ();
}
}
public class ViewInitializedEventArgs
{
public VisualElement View { get; set; }
public Ooui.Element NativeView { get; set; }
}
}
}

View File

@ -5,5 +5,14 @@ namespace Ooui.Forms
{
public interface IVisualElementRenderer : IRegisterable, IDisposable
{
event EventHandler<VisualElementChangedEventArgs> ElementChanged;
VisualElement Element { get; }
Ooui.Element NativeView { get; }
void SetElement (VisualElement element);
void SetElementSize (Size size);
}
}

View File

@ -9,6 +9,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Renderers\" />
<Folder Include="Extensions\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Ooui\Ooui.csproj" />

View File

@ -11,7 +11,9 @@ namespace Ooui.Forms
{
bool _disposed;
public Element Element { get; private set; }
readonly PlatformRenderer _renderer;
public Ooui.Element Element => _renderer;
public Page Page { get; private set; }
@ -26,6 +28,11 @@ namespace Ooui.Forms
view.IsPlatformEnabled = newvalue != null;
});
public Platform ()
{
_renderer = new PlatformRenderer (this);
}
void IDisposable.Dispose()
{
if (_disposed)
@ -40,7 +47,7 @@ namespace Ooui.Forms
public static IVisualElementRenderer CreateRenderer (VisualElement element)
{
var renderer = Registrar.Registered.GetHandler<IVisualElementRenderer> (element.GetType ()) ?? new DefaultRenderer ();
//renderer.SetElement (element);
renderer.SetElement (element);
return renderer;
}
@ -77,11 +84,16 @@ namespace Ooui.Forms
Page.Platform = this;
AddChild (Page);
//Page.DescendantRemoved += HandleChildRemoved;
Page.DescendantRemoved += HandleChildRemoved;
Application.Current.NavigationProxy.Inner = this;
}
void HandleChildRemoved (object sender, ElementEventArgs e)
{
throw new NotImplementedException ();
}
void AddChild (VisualElement view)
{
if (!Application.IsApplicationOrNull (view.RealParent))
@ -91,11 +103,8 @@ namespace Ooui.Forms
var viewRenderer = CreateRenderer (view);
SetRenderer (view, viewRenderer);
//_renderer.View.AddSubview (viewRenderer.NativeView);
//if (viewRenderer.ViewController != null)
// _renderer.AddChildViewController (viewRenderer.ViewController);
//viewRenderer.NativeView.Frame = new RectangleF (0, 0, _renderer.View.Bounds.Width, _renderer.View.Bounds.Height);
//viewRenderer.SetElementSize (new Size (_renderer.View.Bounds.Width, _renderer.View.Bounds.Height));
_renderer.AppendChild (viewRenderer.NativeView);
viewRenderer.SetElementSize (new Size (640, 480));
}
else
Console.Error.WriteLine ("Potential view double add");

View File

@ -0,0 +1,9 @@
using System;
using Xamarin.Forms;
namespace Ooui.Forms
{
public abstract class PlatformEffect : PlatformEffect<Ooui.Element, Ooui.Element>
{
}
}

View File

@ -0,0 +1,17 @@
using System;
using Xamarin.Forms;
namespace Ooui.Forms
{
public class PlatformRenderer : Ooui.Div
{
readonly Platform platform;
public Platform Platform => platform;
public PlatformRenderer (Platform platform)
{
this.platform = platform;
}
}
}

View File

@ -3,7 +3,7 @@ using Xamarin.Forms;
namespace Ooui.Forms.Renderers
{
public class ButtonRenderer : ElementRenderer<Xamarin.Forms.Button, Ooui.Button>
public class ButtonRenderer : ViewRenderer<Xamarin.Forms.Button, Ooui.Button>
{
public ButtonRenderer()
{

View File

@ -5,7 +5,7 @@ namespace Ooui.Forms.Renderers
{
public class DefaultRenderer : VisualElementRenderer<VisualElement>
{
public DefaultRenderer () : base ("div")
public DefaultRenderer ()
{
}
}

View File

@ -1,42 +0,0 @@
using System;
using Xamarin.Forms;
namespace Ooui.Forms.Renderers
{
public class ElementRenderer<TElement, TNativeElement> : IVisualElementRenderer where TElement : View where TNativeElement : Ooui.Element
{
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose (bool disposing)
{
if (!disposedValue) {
if (disposing) {
// TODO: dispose managed state (managed objects).
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~ElementRenderer() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose ()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose (true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
}
}

View File

@ -0,0 +1,116 @@
using System;
using System.ComponentModel;
using Ooui.Forms.Extensions;
using Xamarin.Forms;
namespace Ooui.Forms.Renderers
{
public class ViewRenderer<TElement, TNativeElement> : VisualElementRenderer<TElement> where TElement : View where TNativeElement : Ooui.Element
{
Color _defaultColor;
public TNativeElement Control { get; private set; }
/// <summary>
/// Determines whether the native control is disposed of when this renderer is disposed
/// Can be overridden in deriving classes
/// </summary>
protected virtual bool ManageNativeControlLifetime => true;
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
if (disposing && Control != null && ManageNativeControlLifetime) {
Control = null;
}
}
protected override void OnElementChanged (ElementChangedEventArgs<TElement> e)
{
base.OnElementChanged (e);
if (e.OldElement != null)
e.OldElement.FocusChangeRequested -= ViewOnFocusChangeRequested;
if (e.NewElement != null) {
if (Control != null && e.OldElement != null && e.OldElement.BackgroundColor != e.NewElement.BackgroundColor || e.NewElement.BackgroundColor != Xamarin.Forms.Color.Default)
SetBackgroundColor (e.NewElement.BackgroundColor);
e.NewElement.FocusChangeRequested += ViewOnFocusChangeRequested;
}
UpdateIsEnabled ();
}
protected override void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (Control != null) {
if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
UpdateIsEnabled ();
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
SetBackgroundColor (Element.BackgroundColor);
}
base.OnElementPropertyChanged (sender, e);
}
protected override void OnRegisterEffect (PlatformEffect effect)
{
base.OnRegisterEffect (effect);
//effect.Control = Control;
}
protected override void SetAutomationId (string id)
{
if (Control == null)
base.SetAutomationId (id);
else {
}
}
protected override void SetBackgroundColor (Xamarin.Forms.Color color)
{
if (Control == null)
return;
if (color == Xamarin.Forms.Color.Default)
Control.Style.BackgroundColor = _defaultColor;
else
Control.Style.BackgroundColor = color.ToOouiColor ();
}
protected void SetNativeControl (Ooui.Element uiview)
{
_defaultColor = Color.FromStyleValue (uiview.Style.BackgroundColor);
Control = (TNativeElement)uiview;
if (Element.BackgroundColor != Xamarin.Forms.Color.Default)
SetBackgroundColor (Element.BackgroundColor);
UpdateIsEnabled ();
this.AppendChild (uiview);
}
protected override void SendVisualElementInitialized (VisualElement element, Ooui.Element nativeView)
{
base.SendVisualElementInitialized (element, Control);
}
void UpdateIsEnabled ()
{
if (Element == null || Control == null)
return;
var uiControl = Control as Ooui.Element;
if (uiControl == null)
return;
uiControl.IsDisabled = !Element.IsEnabled;
}
void ViewOnFocusChangeRequested (object sender, VisualElement.FocusRequestArgs focusRequestArgs)
{
}
}
}

View File

@ -1,12 +1,133 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Ooui.Forms.Extensions;
using Xamarin.Forms;
namespace Ooui.Forms
{
public class VisualElementRenderer<TElement> : Element, IVisualElementRenderer where TElement : VisualElement
public class VisualElementRenderer<TElement> : Ooui.Element, IVisualElementRenderer where TElement : VisualElement
{
public VisualElementRenderer (string tagName) : base (tagName)
readonly Color _defaultColor = Color.Clear;
readonly PropertyChangedEventHandler _propertyChangedHandler;
public TElement Element { get; private set; }
VisualElement IVisualElementRenderer.Element => Element;
public Element NativeView => this;
event EventHandler<VisualElementChangedEventArgs> IVisualElementRenderer.ElementChanged {
add { _elementChangedHandlers.Add (value); }
remove { _elementChangedHandlers.Remove (value); }
}
readonly List<EventHandler<VisualElementChangedEventArgs>> _elementChangedHandlers =
new List<EventHandler<VisualElementChangedEventArgs>> ();
public VisualElementRenderer () : base ("div")
{
_propertyChangedHandler = OnElementPropertyChanged;
}
protected virtual void OnElementChanged (ElementChangedEventArgs<TElement> e)
{
var args = new VisualElementChangedEventArgs (e.OldElement, e.NewElement);
for (int i = 0; i < _elementChangedHandlers.Count; i++) {
_elementChangedHandlers[i] (this, args);
}
var changed = ElementChanged;
if (changed != null)
changed (this, e);
}
public event EventHandler<ElementChangedEventArgs<TElement>> ElementChanged;
void IVisualElementRenderer.SetElement (VisualElement element)
{
SetElement ((TElement)element);
}
public void SetElement (TElement element)
{
var oldElement = Element;
Element = element;
if (oldElement != null)
oldElement.PropertyChanged -= _propertyChangedHandler;
if (element != null) {
if (element.BackgroundColor != Xamarin.Forms.Color.Default || (oldElement != null && element.BackgroundColor != oldElement.BackgroundColor))
SetBackgroundColor (element.BackgroundColor);
//if (_tracker == null) {
// _tracker = new VisualElementTracker (this);
// _tracker.NativeControlUpdated += (sender, e) => UpdateNativeWidget ();
//}
//if (AutoPackage && _packager == null) {
// _packager = new VisualElementPackager (this);
// _packager.Load ();
//}
//if (AutoTrack && _events == null) {
// _events = new EventTracker (this);
// _events.LoadEvents (this);
//}
element.PropertyChanged += _propertyChangedHandler;
}
OnElementChanged (new ElementChangedEventArgs<TElement> (oldElement, element));
if (element != null)
SendVisualElementInitialized (element, this);
if (Element != null && !string.IsNullOrEmpty (Element.AutomationId))
SetAutomationId (Element.AutomationId);
}
public void SetElementSize (Size size)
{
Xamarin.Forms.Layout.LayoutChildIntoBoundingRegion (Element, new Rectangle (Element.X, Element.Y, size.Width, size.Height));
}
protected virtual void OnElementPropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) {
SetBackgroundColor (Element.BackgroundColor);
}
else if (e.PropertyName == Layout.IsClippedToBoundsProperty.PropertyName) {
//UpdateClipToBounds ();
}
}
protected virtual void OnRegisterEffect (PlatformEffect effect)
{
//effect.Container = this;
}
protected virtual void SetAutomationId (string id)
{
}
protected virtual void SetBackgroundColor (Xamarin.Forms.Color color)
{
if (color == Xamarin.Forms.Color.Default)
Style.BackgroundColor = _defaultColor;
else
Style.BackgroundColor = color.ToOouiColor ();
}
protected virtual void UpdateNativeWidget ()
{
}
protected virtual void SendVisualElementInitialized (VisualElement element, Element nativeView)
{
element.SendViewInitialized (nativeView);
}
#region IDisposable Support

View File

@ -81,7 +81,12 @@ Global
$1.scope = text/x-csharp
$0.CSharpFormattingPolicy = $2
$2.scope = text/x-csharp
$2.SpacingAfterMethodDeclarationName = True
$2.SpaceAfterMethodCallName = True
$2.NewLinesForBracesInProperties = False
$2.NewLinesForBracesInAccessors = False
$2.NewLinesForBracesInAnonymousMethods = False
$2.NewLinesForBracesInControlBlocks = False
$2.NewLinesForBracesInAnonymousTypes = False
$2.NewLinesForBracesInObjectCollectionArrayInitializers = False
$2.NewLinesForBracesInLambdaExpressionBody = False
EndGlobalSection
EndGlobal

View File

@ -1,11 +1,23 @@
using System;
using StyleValue = System.Object;
namespace Ooui
{
public struct Color
{
public byte R, G, B, A;
public static Color Clear => new Color (0, 0, 0, 0);
public Color (byte r, byte g, byte b, byte a)
{
R = r;
G = g;
B = b;
A = a;
}
public double Red {
get => R / 255.0;
set => R = value >= 1.0 ? (byte)255 : ((value <= 0.0) ? (byte)0 : (byte)(value * 255.0 + 0.5));
@ -22,5 +34,10 @@ namespace Ooui
get => A / 255.0;
set => A = value >= 1.0 ? (byte)255 : ((value <= 0.0) ? (byte)0 : (byte)(value * 255.0 + 0.5));
}
public static Color FromStyleValue (StyleValue styleColor)
{
return Clear;
}
}
}

View File

@ -25,6 +25,12 @@ namespace Ooui
set => SetProperty (ref hidden, value, "hidden");
}
bool disabled = false;
public bool IsDisabled {
get => disabled;
set => SetProperty (ref disabled, value, "disabled");
}
public event TargetEventHandler Clicked {
add => AddEventListener ("click", value);
remove => RemoveEventListener ("click", value);