Strongly typed handler option and standardize mappers a bit more (#12198)

* strongly typed handler option

* - clean up from meeting notes

* - make spacing consistent

* - PR comments
This commit is contained in:
Shane Neuville 2020-09-22 11:13:46 -05:00 коммит произвёл GitHub
Родитель 8994f08adb
Коммит 66ab07a387
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 233 добавлений и 105 удалений

Просмотреть файл

@ -2,22 +2,32 @@
<ItemGroup Condition="$(TargetFramework.StartsWith('Xamarin.iOS')) != true ">
<Compile Remove="**\*.iOS.cs" />
<None Include="**\*.iOS.cs" />
<Compile Remove="**\iOS\*.cs" />
<None Include="**\iOS\*.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('Xamarin.Mac')) != true ">
<Compile Remove="**\*.Mac.cs" />
<None Include="**\*.Mac.cs" />
<Compile Remove="**\Mac\*.cs" />
<None Include="**\Mac\*.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('Xamarin.Mac')) != true And $(TargetFramework.StartsWith('Xamarin.iOS')) != true ">
<Compile Remove="**\*.MaciOS.cs" />
<None Include="**\*.MaciOS.cs" />
<Compile Remove="**\MaciOS\*.cs" />
<None Include="**\MaciOS\*.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('MonoAndroid')) != true ">
<Compile Remove="**\*.Android.cs" />
<None Include="**\*.Android.cs" />
<Compile Remove="**\Android\*.cs" />
<None Include="**\Android\*.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard')) != true ">
<Compile Remove="**\*.Standard.cs" />
<None Include="**\*.Standard.cs" />
<Compile Remove="**\Standard\*.cs" />
<None Include="**\Standard\*.cs" />
</ItemGroup>
<ItemGroup Condition="$(TargetFramework.StartsWith('netcoreapp')) != true ">
<Compile Remove="**\*.Win32.cs" />
@ -26,13 +36,10 @@
<None Include="**\*.xaml.cs" />
<Compile Remove="**\*.xaml" />
<None Include="**\*.xaml" />
<Compile Remove="**\Win32\*.cs" />
<None Include="**\Win32\*.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Platform\MaciOS\" />
<Folder Include="Platform\iOS\" />
<Folder Include="Platform\Mac\" />
<Folder Include="Platform\Android\" />
</ItemGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith('netcoreapp')) == true ">
<UseWpf>true</UseWpf>
</PropertyGroup>

Просмотреть файл

@ -35,7 +35,7 @@ namespace Sample.Droid
{
foreach (var view in views)
{
_page.AddView(view.ToNative(this), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WrapContent, ViewGroup.LayoutParams.WrapContent));
_page.AddView(view.ToNative(this));
}
}

Просмотреть файл

@ -13,7 +13,7 @@ namespace Sample
public IView CreateView()
{
return new Button() { Text = "Hello I'm a button", BackgroundColor = Color.Purple };
return new Button() { Color = Color.Green , Text = "Hello I'm a button", BackgroundColor = Color.Purple };
}
}
}

Просмотреть файл

@ -1,22 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Platform.Handlers;
namespace Xamarin.Platform
{
public class ActionMapper<TVirtualView>
public class ActionMapper<TVirtualView, TViewHandler>
where TVirtualView : IFrameworkElement
where TViewHandler : IViewHandler
{
public ActionMapper(PropertyMapper<TVirtualView> propertyMapper)
public ActionMapper(PropertyMapper<TVirtualView, TViewHandler> propertyMapper)
{
PropertyMapper = propertyMapper;
}
public PropertyMapper<TVirtualView> PropertyMapper { get; }
public PropertyMapper<TVirtualView, TViewHandler> PropertyMapper { get; }
public Action<IViewHandler, TVirtualView> this[string key]
public Action<TViewHandler, TVirtualView> this[string key]
{
set => PropertyMapper._mapper[key] = ((r, v) => value?.Invoke(r, (TVirtualView)v), false);
set => PropertyMapper._mapper[key] = ((r, v) => value?.Invoke((TViewHandler)r, (TVirtualView)v), false);
}
}
}

Просмотреть файл

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Platform
{
public interface ILabel : IText
{
}
}

Просмотреть файл

@ -1,17 +0,0 @@
using System;
using AndroidX.Core.View;
using AndroidX.AppCompat.Widget;
namespace Xamarin.Platform.Handlers
{
public partial class ButtonHandler : AbstractViewHandler<IButton, AppCompatButton>
{
protected override AppCompatButton CreateView() => new AppCompatButton(Context);
public static void MapText(IViewHandler handler, IButton view)
{
((AppCompatButton)handler.NativeView).Text = view.Text;
}
}
}

Просмотреть файл

@ -1,12 +0,0 @@
using System;
using AppKit;
namespace Xamarin.Platform.Handlers
{
public partial class ButtonHandler : AbstractViewHandler<IButton, NSButton>
{
protected override NSButton CreateView() => throw new NotImplementedException();
public static void MapText(IViewHandler handler, IButton view) { }
}
}

Просмотреть файл

@ -1,11 +0,0 @@
using System;
namespace Xamarin.Platform.Handlers
{
public partial class ButtonHandler : AbstractViewHandler<IButton, object>
{
public static void MapText(IViewHandler handler, IButton view) { }
protected override object CreateView() => throw new NotImplementedException();
}
}

Просмотреть файл

@ -1,21 +1,42 @@
using System;
#if __IOS__
using NativeView = UIKit.UIButton;
#elif __MACOS__
using NativeView = AppKit.NSButton;
#elif MONOANDROID
using NativeView = AndroidX.AppCompat.Widget.AppCompatButton;
#elif NETCOREAPP
using NativeView = System.Windows.Controls.Button;
#elif NETSTANDARD
using NativeView = System.Object;
#endif
namespace Xamarin.Platform.Handlers
{
public partial class ButtonHandler
public partial class ButtonHandler : AbstractViewHandler<IButton, NativeView>
{
public static PropertyMapper<IButton> ButtonMapper = new PropertyMapper<IButton>(ViewHandler.ViewMapper)
public static PropertyMapper<IButton, ButtonHandler> ButtonMapper = new PropertyMapper<IButton, ButtonHandler>(ViewHandler.ViewMapper)
{
[nameof(IButton.Text)] = MapText,
Actions = {
["DemoAction"] = DemoAction
}
[nameof(IButton.Color)] = MapColor
};
private static void DemoAction(IViewHandler arg1, IButton arg2)
public static void MapColor(ButtonHandler handler, IButton button)
{
handler.TypedNativeView.UpdateColor(button);
}
public static void MapText(ButtonHandler handler, IButton button)
{
handler.TypedNativeView.UpdateText(button);
}
#if MONOANDROID
protected override NativeView CreateView() => new NativeView(this.Context);
#else
protected override NativeView CreateView() => new NativeView();
#endif
public ButtonHandler() : base(ButtonMapper)
{

Просмотреть файл

@ -1,15 +0,0 @@
using System;
using UIKit;
namespace Xamarin.Platform.Handlers
{
public partial class ButtonHandler : AbstractViewHandler<IButton, UIButton>
{
protected override UIButton CreateView() => new UIButton();
public static void MapText(IViewHandler handler, IButton view)
{
((UIButton)handler.NativeView).SetText(view.Text);
}
}
}

Просмотреть файл

@ -0,0 +1,43 @@
using System;
#if __IOS__
using NativeView = UIKit.UILabel;
#elif __MACOS__
using NativeView = AppKit.NSTextField;
#elif MONOANDROID
using NativeView = Android.Widget.TextView;
#elif NETCOREAPP
using NativeView = System.Windows.Controls.TextBlock;
#elif NETSTANDARD
using NativeView = System.Object;
#endif
namespace Xamarin.Platform.Handlers
{
public partial class LabelHandler : AbstractViewHandler<ILabel, NativeView>
{
public static PropertyMapper<ILabel, LabelHandler> LabelMapper = new PropertyMapper<ILabel, LabelHandler>(ViewHandler.ViewMapper)
{
[nameof(ILabel.Color)] = MapColor
};
public static void MapColor(LabelHandler handler, ILabel Label)
{
}
#if MONOANDROID
protected override NativeView CreateView() => new NativeView(this.Context);
#else
protected override NativeView CreateView() => new NativeView();
#endif
public LabelHandler() : base(LabelMapper)
{
}
public LabelHandler(PropertyMapper mapper) : base(mapper ?? LabelMapper)
{
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;
using AndroidX.AppCompat.Widget;
namespace Xamarin.Platform
{
public static class ButtonExtensions
{
public static void UpdateColor(this AppCompatButton appCompatButton, IButton button) =>
appCompatButton.SetTextColor(button.Color.ToNative());
public static void UpdateText(this AppCompatButton appCompatButton, IButton button) =>
appCompatButton.Text = button.Text;
}
}

Просмотреть файл

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;
using AndroidX.AppCompat.Widget;
namespace Xamarin.Platform
{
public static class ButtonExtensions
{
public static void UpdateColor(this IButton button, NSButton button)
{
}
}
}

Просмотреть файл

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Platform
{
public static class ButtonExtensions
{
public static void UpdateColor(this object nothing, IButton button)
{
}
public static void UpdateText(this object nothing, IButton button)
{
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
using UIKit;
namespace Xamarin.Platform
{
public static class ButtonExtensions
{
public static void UpdateColor(this UIButton nativeButton, IButton button)
{
// appCompatButton.SetTextColor(button.Color.ToNative());
}
public static void UpdateText(this UIButton nativeButton, IButton button) => nativeButton.SetText(button.Text);
}
}

Просмотреть файл

@ -64,8 +64,9 @@ namespace Xamarin.Platform
public virtual IReadOnlyList<string> UpdateKeys => updateKeys ?? PopulateKeys(ref updateKeys);
}
public class PropertyMapper<TVirtualView> : PropertyMapper, IEnumerable
public class PropertyMapper<TVirtualView, TViewHandler> : PropertyMapper, IEnumerable
where TVirtualView : IFrameworkElement
where TViewHandler : IViewHandler
{
private PropertyMapper chained;
public PropertyMapper Chained
@ -85,7 +86,7 @@ namespace Xamarin.Platform
public bool IsReadOnly => false;
public Action<IViewHandler, TVirtualView> this[string key]
public Action<TViewHandler, TVirtualView> this[string key]
{
set => Add(key, value, true);
}
@ -99,10 +100,10 @@ namespace Xamarin.Platform
Chained = chained;
}
ActionMapper<TVirtualView> actions;
public ActionMapper<TVirtualView> Actions
ActionMapper<TVirtualView, TViewHandler> actions;
public ActionMapper<TVirtualView, TViewHandler> Actions
{
get => actions ??= new ActionMapper<TVirtualView>(this);
get => actions ??= new ActionMapper<TVirtualView, TViewHandler>(this);
}
protected override void ClearKeyCache()
@ -121,17 +122,27 @@ namespace Xamarin.Platform
return Chained?.Get(key) ?? (null, false);
}
public void Add(string key, Action<IViewHandler, TVirtualView> action)
public void Add(string key, Action<TViewHandler, TVirtualView> action)
=> this[key] = action;
public void Add(string key, Action<IViewHandler, TVirtualView> action, bool ignoreOnStartup)
=> _mapper[key] = ((r, v) => action?.Invoke(r, (TVirtualView)v), ignoreOnStartup);
public void Add(string key, Action<TViewHandler, TVirtualView> action, bool ignoreOnStartup)
=> _mapper[key] = ((r, v) => action?.Invoke((TViewHandler)r, (TVirtualView)v), ignoreOnStartup);
IEnumerator IEnumerable.GetEnumerator() => _mapper.GetEnumerator();
}
public class PropertyMapper<TVirtualView> : PropertyMapper<TVirtualView, IViewHandler>
where TVirtualView : IFrameworkElement
{
public PropertyMapper()
{
}
public PropertyMapper(PropertyMapper chained) : base(chained)
{
}
}
}

Просмотреть файл

@ -130,5 +130,28 @@ namespace Xamarin.Platform.Handlers.Tests
Assert.False(mapperActionWasCalled);
Assert.True(wasMapper2Called);
}
[Test]
public void GenericMappersWorks()
{
bool wasMapper1Called = false;
bool wasMapper2Called = false;
var mapper1 = new PropertyMapper<IView, IViewHandler>
{
[nameof(IView.BackgroundColor)] = (r, v) => wasMapper1Called = true
};
var mapper2 = new PropertyMapper<IButton, ButtonHandler>(mapper1)
{
[nameof(IButton.Color)] = (r, v) => wasMapper2Called = true
};
mapper2.UpdateProperties(null, new Button());
Assert.True(wasMapper1Called);
Assert.True(wasMapper2Called);
}
}
}