ViewManager Events (#3684)
* VM: Add support for CustomBubblingEventTypeConstants #3212 * VM: Add support for CustomDirectEventTypeConstants #3213 * Created IReactContext, which is passed in to the ViewManagerProvider delegate, to enable calling CallJSFunction and DispatchEvent from native code (partial #3208) * VMs support "JS-style objects" for event params, property types (partial #3207, #3562)
This commit is contained in:
Родитель
45c209dd66
Коммит
531eef59be
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"type": "prerelease",
|
||||
"comment": "View Manager Event Support",
|
||||
"packageName": "react-native-windows",
|
||||
"email": "jthysell@microsoft.com",
|
||||
"commit": "a016d6d6709dcd01de300a1136756e36ba3b5070",
|
||||
"date": "2019-11-25T20:09:28.093Z"
|
||||
}
|
|
@ -148,6 +148,16 @@ class SampleApp extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
onLabelChangedCustomUserControlCS(evt) {
|
||||
var label = evt.nativeEvent;
|
||||
log(`SampleApp.onLabelChangedCustomUserControlCS("${label}")`);
|
||||
}
|
||||
|
||||
onLabelChangedCustomUserControlCPP(evt) {
|
||||
var label = evt.nativeEvent;
|
||||
log(`SampleApp.onLabelChangedCustomUserControlCPP("${label}")`);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
|
@ -161,10 +171,10 @@ class SampleApp extends Component {
|
|||
<Button onPress={() => { this.onPressSampleModuleCS(); }} title="Call SampleModuleCS!" disabled={NativeModules.SampleModuleCS == null} />
|
||||
<Button onPress={() => { this.onPressSampleModuleCPP(); }} title="Call SampleModuleCPP!" disabled={NativeModules.SampleModuleCPP == null} />
|
||||
|
||||
<CustomUserControlCS style={styles.customcontrol} label="CustomUserControlCS!" ref={(ref) => { this._CustomUserControlCSRef = ref; }} />
|
||||
<CustomUserControlCS style={styles.customcontrol} label="CustomUserControlCS!" ref={(ref) => { this._CustomUserControlCSRef = ref; }} onLabelChanged={(evt) => { this.onLabelChangedCustomUserControlCS(evt); }} />
|
||||
<Button onPress={() => { this.onPressCustomUserControlCS(); }} title="Call CustomUserControlCS Commands!" />
|
||||
|
||||
<CustomUserControlCPP style={styles.customcontrol} label="CustomUserControlCPP!" ref={(ref) => { this._CustomUserControlCPPRef = ref; }} />
|
||||
<CustomUserControlCPP style={styles.customcontrol} label="CustomUserControlCPP!" ref={(ref) => { this._CustomUserControlCPPRef = ref; }} onLabelChanged={(evt) => { this.onLabelChangedCustomUserControlCPP(evt); }} />
|
||||
<Button onPress={() => { this.onPressCustomUserControlCPP(); }} title="Call CustomUserControlCPP Commands!" />
|
||||
|
||||
<Text style={styles.instructions}>
|
||||
|
|
|
@ -18,13 +18,31 @@ using namespace Windows::UI::Xaml::Controls;
|
|||
|
||||
namespace winrt::SampleLibraryCPP::implementation {
|
||||
|
||||
CustomUserControlViewManagerCPP::CustomUserControlViewManagerCPP(IReactContext const &reactContext)
|
||||
: m_reactContext{reactContext} {}
|
||||
|
||||
IReactContext CustomUserControlViewManagerCPP::ReactContext() noexcept {
|
||||
return m_reactContext;
|
||||
}
|
||||
|
||||
// IViewManager
|
||||
hstring CustomUserControlViewManagerCPP::Name() noexcept {
|
||||
return L"CustomUserControlCPP";
|
||||
}
|
||||
|
||||
FrameworkElement CustomUserControlViewManagerCPP::CreateView() noexcept {
|
||||
return winrt::SampleLibraryCPP::CustomUserControlCPP();
|
||||
auto const &view = winrt::SampleLibraryCPP::CustomUserControlCPP();
|
||||
|
||||
view.RegisterPropertyChangedCallback(
|
||||
winrt::SampleLibraryCPP::CustomUserControlCPP::LabelProperty(),
|
||||
[this](
|
||||
winrt::Windows::UI::Xaml::DependencyObject obj, winrt::Windows::UI::Xaml::DependencyProperty prop) noexcept {
|
||||
if (auto c = obj.try_as<winrt::SampleLibraryCPP::CustomUserControlCPP>()) {
|
||||
ReactContext().DispatchEvent(c, L"topLabelChanged", box_value(c.Label()));
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
// IViewManagerWithNativeProperties
|
||||
|
@ -92,4 +110,21 @@ void CustomUserControlViewManagerCPP::DispatchCommand(
|
|||
}
|
||||
}
|
||||
|
||||
// IViewManagerWithExportedEventTypeConstants
|
||||
IMapView<hstring, IInspectable> CustomUserControlViewManagerCPP::ExportedCustomBubblingEventTypeConstants() noexcept {
|
||||
auto constants = winrt::single_threaded_map<hstring, IInspectable>();
|
||||
return constants.GetView();
|
||||
}
|
||||
|
||||
IMapView<hstring, IInspectable> CustomUserControlViewManagerCPP::ExportedCustomDirectEventTypeConstants() noexcept {
|
||||
auto constants = winrt::single_threaded_map<hstring, IInspectable>();
|
||||
|
||||
auto registration = winrt::single_threaded_map<hstring, IInspectable>();
|
||||
registration.Insert(L"registrationName", box_value(L"onLabelChanged"));
|
||||
|
||||
constants.Insert(L"topLabelChanged", registration.GetView());
|
||||
|
||||
return constants.GetView();
|
||||
}
|
||||
|
||||
} // namespace winrt::SampleLibraryCPP::implementation
|
||||
|
|
|
@ -7,17 +7,21 @@
|
|||
|
||||
namespace winrt::SampleLibraryCPP::implementation {
|
||||
|
||||
struct CustomUserControlViewManagerCPP : winrt::implements<
|
||||
CustomUserControlViewManagerCPP,
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManager,
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithNativeProperties,
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithCommands> {
|
||||
struct CustomUserControlViewManagerCPP
|
||||
: winrt::implements<
|
||||
CustomUserControlViewManagerCPP,
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManager,
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithNativeProperties,
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithCommands,
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithExportedEventTypeConstants> {
|
||||
public:
|
||||
CustomUserControlViewManagerCPP() = default;
|
||||
CustomUserControlViewManagerCPP(winrt::Microsoft::ReactNative::Bridge::IReactContext const &reactContext);
|
||||
|
||||
// IViewManager
|
||||
winrt::hstring Name() noexcept;
|
||||
|
||||
winrt::Microsoft::ReactNative::Bridge::IReactContext ReactContext() noexcept;
|
||||
|
||||
winrt::Windows::UI::Xaml::FrameworkElement CreateView() noexcept;
|
||||
|
||||
// IViewManagerWithNativeProperties
|
||||
|
@ -38,6 +42,16 @@ struct CustomUserControlViewManagerCPP : winrt::implements<
|
|||
int64_t commandId,
|
||||
winrt::Windows::Foundation::Collections::IVectorView<winrt::Windows::Foundation::IInspectable>
|
||||
commandArgs) noexcept;
|
||||
|
||||
// IViewManagerWithExportedEventTypeConstants
|
||||
winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Windows::Foundation::IInspectable>
|
||||
ExportedCustomBubblingEventTypeConstants() noexcept;
|
||||
|
||||
winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, winrt::Windows::Foundation::IInspectable>
|
||||
ExportedCustomDirectEventTypeConstants() noexcept;
|
||||
|
||||
private:
|
||||
winrt::Microsoft::ReactNative::Bridge::IReactContext m_reactContext{nullptr};
|
||||
};
|
||||
|
||||
} // namespace winrt::SampleLibraryCPP::implementation
|
||||
|
|
|
@ -17,8 +17,9 @@ namespace winrt::SampleLibraryCPP::implementation {
|
|||
|
||||
void ReactPackageProvider::CreatePackage(IReactPackageBuilder const &packageBuilder) noexcept {
|
||||
AddAttributedModules(packageBuilder);
|
||||
packageBuilder.AddViewManager(
|
||||
L"CustomUserControlViewManagerCPP", []() { return winrt::make<CustomUserControlViewManagerCPP>(); });
|
||||
packageBuilder.AddViewManager(L"CustomUserControlViewManagerCPP", [](IReactContext const &reactContext) {
|
||||
return winrt::make<CustomUserControlViewManagerCPP>(reactContext);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace winrt::SampleLibraryCPP::implementation
|
||||
|
|
|
@ -1,16 +1,35 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
using Microsoft.ReactNative.Managed;
|
||||
using Microsoft.ReactNative.Bridge;
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace SampleLibraryCS
|
||||
{
|
||||
internal class CustomUserControlViewManagerCS : AttributedViewManager<CustomUserControlCS>
|
||||
{
|
||||
public CustomUserControlViewManagerCS(IReactContext reactContext) : base(reactContext) { }
|
||||
|
||||
public override FrameworkElement CreateView()
|
||||
{
|
||||
var view = new CustomUserControlCS();
|
||||
view.RegisterPropertyChangedCallback(CustomUserControlCS.LabelProperty, (obj, prop) =>
|
||||
{
|
||||
if (obj is CustomUserControlCS c)
|
||||
{
|
||||
LabelChanged(c, c.Label);
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
[ViewManagerProperty("label")]
|
||||
public void SetLabel(CustomUserControlCS view, string value)
|
||||
{
|
||||
|
@ -55,5 +74,8 @@ namespace SampleLibraryCS
|
|||
{
|
||||
Debug.WriteLine($"{Name}.{nameof(CustomCommand)}({view.Tag}, \"{arg}\")");
|
||||
}
|
||||
|
||||
[ViewManagerExportedDirectEventTypeConstant]
|
||||
public ViewManagerEvent<CustomUserControlCS, string> LabelChanged;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
@ -11,23 +12,66 @@ using Microsoft.ReactNative.Bridge;
|
|||
|
||||
namespace Microsoft.ReactNative.Managed
|
||||
{
|
||||
internal abstract class AttributedViewManager<T> :
|
||||
internal abstract class AttributedViewManager<TFrameworkElement> :
|
||||
IViewManager,
|
||||
IViewManagerWithExportedViewConstants,
|
||||
IViewManagerWithNativeProperties,
|
||||
IViewManagerWithCommands
|
||||
where T : FrameworkElement, new()
|
||||
IViewManagerWithCommands,
|
||||
IViewManagerWithExportedEventTypeConstants
|
||||
where TFrameworkElement : FrameworkElement, new()
|
||||
{
|
||||
public virtual string Name => typeof(T).Name;
|
||||
public IReactContext ReactContext { get; private set; }
|
||||
|
||||
public virtual FrameworkElement CreateView() => new T();
|
||||
protected AttributedViewManager(IReactContext reactContext)
|
||||
{
|
||||
ReactContext = reactContext;
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, object> ExportedViewConstants => _exportedViewConstants ?? (_exportedViewConstants = GetConstantsByAttribute<ViewManagerExportedViewConstantAttribute>());
|
||||
#region IViewManager
|
||||
|
||||
public virtual string Name => typeof(TFrameworkElement).Name;
|
||||
|
||||
public virtual FrameworkElement CreateView() => new TFrameworkElement();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
|
||||
public virtual IReadOnlyDictionary<string, object> ExportedViewConstants => _exportedViewConstants ?? (_exportedViewConstants = GetExportedViewConstants());
|
||||
private IReadOnlyDictionary<string, object> _exportedViewConstants;
|
||||
|
||||
private IReadOnlyDictionary<string, object> GetExportedViewConstants()
|
||||
{
|
||||
var typeInfo = GetType().GetTypeInfo();
|
||||
|
||||
var constants = new Dictionary<string, object>();
|
||||
|
||||
foreach (var fieldInfo in typeInfo.DeclaredFields)
|
||||
{
|
||||
var attribute = fieldInfo.GetCustomAttribute<ViewManagerExportedViewConstantAttribute>();
|
||||
if (null != attribute)
|
||||
{
|
||||
constants.Add(attribute.ConstantName ?? fieldInfo.Name, fieldInfo.GetValue(this));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var propertyInfo in typeInfo.DeclaredProperties)
|
||||
{
|
||||
var attribute = propertyInfo.GetCustomAttribute<ViewManagerExportedViewConstantAttribute>();
|
||||
if (null != attribute)
|
||||
{
|
||||
constants.Add(attribute.ConstantName ?? propertyInfo.Name, propertyInfo.GetMethod.Invoke(this, null));
|
||||
}
|
||||
}
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public IReadOnlyDictionary<string, ViewManagerPropertyType> NativeProps
|
||||
public virtual IReadOnlyDictionary<string, ViewManagerPropertyType> NativeProps
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -47,22 +91,40 @@ namespace Microsoft.ReactNative.Managed
|
|||
}
|
||||
private IReadOnlyDictionary<string, ViewManagerPropertyType> _nativeProps;
|
||||
|
||||
internal Dictionary<string, ViewManagerProperty<T>> ViewManagerProperties
|
||||
public virtual void UpdateProperties(FrameworkElement view, IReadOnlyDictionary<string, object> propertyMap)
|
||||
{
|
||||
if (view is TFrameworkElement viewAsT)
|
||||
{
|
||||
foreach (var property in propertyMap)
|
||||
{
|
||||
if (ViewManagerProperties.TryGetValue(property.Key, out ViewManagerProperty<TFrameworkElement> setter))
|
||||
{
|
||||
setter.Setter(viewAsT, property.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(view));
|
||||
}
|
||||
}
|
||||
|
||||
internal Dictionary<string, ViewManagerProperty<TFrameworkElement>> ViewManagerProperties
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _properties)
|
||||
{
|
||||
var properties = new Dictionary<string, ViewManagerProperty<T>>();
|
||||
var properties = new Dictionary<string, ViewManagerProperty<TFrameworkElement>>();
|
||||
|
||||
foreach (var methodInfo in GetType().GetTypeInfo().DeclaredMethods)
|
||||
{
|
||||
var propertyAttribute = methodInfo.GetCustomAttribute<ViewManagerPropertyAttribute>();
|
||||
if (null != propertyAttribute)
|
||||
{
|
||||
var setter = new ViewManagerProperty<T>();
|
||||
setter.Name = propertyAttribute.Name ?? methodInfo.Name;
|
||||
setter.Type = propertyAttribute.Type ?? TypeToViewManagerPropertyType(methodInfo.GetParameters()[1].ParameterType);
|
||||
var setter = new ViewManagerProperty<TFrameworkElement>();
|
||||
setter.Name = propertyAttribute.PropertyName ?? methodInfo.Name;
|
||||
setter.Type = propertyAttribute.PropertyType ?? TypeToViewManagerPropertyType(methodInfo.GetParameters()[1].ParameterType);
|
||||
setter.Setter = MakePropertySetterMethod(methodInfo);
|
||||
|
||||
properties.Add(setter.Name, setter);
|
||||
|
@ -75,33 +137,31 @@ namespace Microsoft.ReactNative.Managed
|
|||
return _properties;
|
||||
}
|
||||
}
|
||||
private Dictionary<string, ViewManagerProperty<T>> _properties;
|
||||
private Dictionary<string, ViewManagerProperty<TFrameworkElement>> _properties;
|
||||
|
||||
public void UpdateProperties(FrameworkElement view, IReadOnlyDictionary<string, object> propertyMap)
|
||||
{
|
||||
if (view is T viewAsT)
|
||||
{
|
||||
foreach (var property in propertyMap)
|
||||
{
|
||||
if (ViewManagerProperties.TryGetValue(property.Key, out ViewManagerProperty<T> setter))
|
||||
{
|
||||
setter.Setter(viewAsT, property.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(view));
|
||||
}
|
||||
}
|
||||
|
||||
internal struct ViewManagerProperty<U> where U : T
|
||||
internal struct ViewManagerProperty<U> where U : TFrameworkElement
|
||||
{
|
||||
public string Name;
|
||||
public ViewManagerPropertyType Type;
|
||||
public Action<U, object> Setter;
|
||||
}
|
||||
|
||||
private Action<TFrameworkElement, object> MakePropertySetterMethod(MethodInfo methodInfo)
|
||||
{
|
||||
var parameters = methodInfo.GetParameters();
|
||||
|
||||
if (parameters.Length == 2
|
||||
&& parameters[0].ParameterType == typeof(TFrameworkElement))
|
||||
{
|
||||
return (view, propertyValue) =>
|
||||
{
|
||||
methodInfo.Invoke(this, new object[] { view, propertyValue });
|
||||
};
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Unable to parse parameters for {methodInfo.Name}.");
|
||||
}
|
||||
|
||||
private static ViewManagerPropertyType TypeToViewManagerPropertyType(Type t)
|
||||
{
|
||||
if (t == typeof(bool) || t == typeof(bool?))
|
||||
|
@ -112,7 +172,7 @@ namespace Microsoft.ReactNative.Managed
|
|||
{
|
||||
return ViewManagerPropertyType.String;
|
||||
}
|
||||
else if (t == typeof(decimal) || t == typeof(double) || t == typeof(float) || t == typeof(long) || t == typeof(int) || t== typeof(short) || t == typeof(sbyte) || t == typeof(ulong) || t == typeof(uint) || t == typeof(ushort) || t == typeof(byte) ||
|
||||
else if (t == typeof(decimal) || t == typeof(double) || t == typeof(float) || t == typeof(long) || t == typeof(int) || t == typeof(short) || t == typeof(sbyte) || t == typeof(ulong) || t == typeof(uint) || t == typeof(ushort) || t == typeof(byte) ||
|
||||
t == typeof(decimal?) || t == typeof(double?) || t == typeof(float?) || t == typeof(long?) || t == typeof(int?) || t == typeof(sbyte?) || t == typeof(ulong?) || t == typeof(uint?) || t == typeof(ushort?) || t == typeof(byte?))
|
||||
{
|
||||
return ViewManagerPropertyType.Number;
|
||||
|
@ -137,7 +197,7 @@ namespace Microsoft.ReactNative.Managed
|
|||
|
||||
#region Commands
|
||||
|
||||
public IReadOnlyDictionary<string, long> Commands
|
||||
public virtual IReadOnlyDictionary<string, long> Commands
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -157,39 +217,11 @@ namespace Microsoft.ReactNative.Managed
|
|||
}
|
||||
private IReadOnlyDictionary<string, long> _commands;
|
||||
|
||||
internal Dictionary<long, ViewManagerCommand<T>> ViewManagerCommands
|
||||
public virtual void DispatchCommand(FrameworkElement view, long commandId, IReadOnlyList<object> commandArgs)
|
||||
{
|
||||
get
|
||||
if (view is TFrameworkElement viewAsT)
|
||||
{
|
||||
if (null == _viewManagerCommands)
|
||||
{
|
||||
var viewManagerCommands = new Dictionary<long, ViewManagerCommand<T>>();
|
||||
|
||||
foreach (var methodInfo in GetType().GetTypeInfo().DeclaredMethods)
|
||||
{
|
||||
var commandAttribute = methodInfo.GetCustomAttribute<ViewManagerCommandAttribute>();
|
||||
if (null != commandAttribute)
|
||||
{
|
||||
var command = new ViewManagerCommand<T>();
|
||||
command.CommandName = commandAttribute.Name ?? methodInfo.Name;
|
||||
command.CommandId = commandAttribute.CommandId ?? viewManagerCommands.Count;
|
||||
command.CommandMethod = MakeCommandMethod(methodInfo);
|
||||
viewManagerCommands.Add(command.CommandId, command);
|
||||
}
|
||||
}
|
||||
|
||||
_viewManagerCommands = viewManagerCommands;
|
||||
}
|
||||
return _viewManagerCommands;
|
||||
}
|
||||
}
|
||||
private Dictionary<long, ViewManagerCommand<T>> _viewManagerCommands;
|
||||
|
||||
public void DispatchCommand(FrameworkElement view, long commandId, IReadOnlyList<object> commandArgs)
|
||||
{
|
||||
if (view is T viewAsT)
|
||||
{
|
||||
if (ViewManagerCommands.TryGetValue(commandId, out ViewManagerCommand<T> command))
|
||||
if (ViewManagerCommands.TryGetValue(commandId, out ViewManagerCommand<TFrameworkElement> command))
|
||||
{
|
||||
command.CommandMethod(viewAsT, commandArgs);
|
||||
}
|
||||
|
@ -200,38 +232,46 @@ namespace Microsoft.ReactNative.Managed
|
|||
}
|
||||
}
|
||||
|
||||
internal struct ViewManagerCommand<U> where U : T
|
||||
internal Dictionary<long, ViewManagerCommand<TFrameworkElement>> ViewManagerCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
if (null == _viewManagerCommands)
|
||||
{
|
||||
var viewManagerCommands = new Dictionary<long, ViewManagerCommand<TFrameworkElement>>();
|
||||
|
||||
foreach (var methodInfo in GetType().GetTypeInfo().DeclaredMethods)
|
||||
{
|
||||
var commandAttribute = methodInfo.GetCustomAttribute<ViewManagerCommandAttribute>();
|
||||
if (null != commandAttribute)
|
||||
{
|
||||
var command = new ViewManagerCommand<TFrameworkElement>();
|
||||
command.CommandName = commandAttribute.CommandName ?? methodInfo.Name;
|
||||
command.CommandId = viewManagerCommands.Count;
|
||||
command.CommandMethod = MakeCommandMethod(methodInfo);
|
||||
viewManagerCommands.Add(command.CommandId, command);
|
||||
}
|
||||
}
|
||||
|
||||
_viewManagerCommands = viewManagerCommands;
|
||||
}
|
||||
return _viewManagerCommands;
|
||||
}
|
||||
}
|
||||
private Dictionary<long, ViewManagerCommand<TFrameworkElement>> _viewManagerCommands;
|
||||
|
||||
internal struct ViewManagerCommand<U> where U : TFrameworkElement
|
||||
{
|
||||
public string CommandName;
|
||||
public long CommandId;
|
||||
public Action<U, IReadOnlyList<object>> CommandMethod;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Reflection Helpers
|
||||
|
||||
private Action<T, object> MakePropertySetterMethod(MethodInfo methodInfo)
|
||||
{
|
||||
var parameters = methodInfo.GetParameters();
|
||||
|
||||
if (parameters.Length == 2
|
||||
&& parameters[0].ParameterType == typeof(T))
|
||||
{
|
||||
return (view, propertyValue) =>
|
||||
{
|
||||
methodInfo.Invoke(this, new object[] { view, propertyValue });
|
||||
};
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Unable to parse parameters for {methodInfo.Name}.");
|
||||
}
|
||||
|
||||
private Action<T, IReadOnlyList<object>> MakeCommandMethod(MethodInfo methodInfo)
|
||||
private Action<TFrameworkElement, IReadOnlyList<object>> MakeCommandMethod(MethodInfo methodInfo)
|
||||
{
|
||||
var parameters = methodInfo.GetParameters();
|
||||
if (parameters.Length == 2
|
||||
&& parameters[0].ParameterType == typeof(T)
|
||||
&& parameters[0].ParameterType == typeof(TFrameworkElement)
|
||||
&& parameters[1].ParameterType == typeof(IReadOnlyList<object>))
|
||||
{
|
||||
return (view, commandArgs) =>
|
||||
|
@ -240,7 +280,7 @@ namespace Microsoft.ReactNative.Managed
|
|||
};
|
||||
}
|
||||
else if (parameters.Length >= 2
|
||||
&& parameters[0].ParameterType == typeof(T))
|
||||
&& parameters[0].ParameterType == typeof(TFrameworkElement))
|
||||
{
|
||||
return (view, commandArgs) =>
|
||||
{
|
||||
|
@ -255,7 +295,17 @@ namespace Microsoft.ReactNative.Managed
|
|||
throw new ArgumentException($"Unable to parse parameters for {methodInfo.Name}.");
|
||||
}
|
||||
|
||||
private IReadOnlyDictionary<string, object> GetConstantsByAttribute<U>() where U : ViewManagerNamedAttribute
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public virtual IReadOnlyDictionary<string, object> ExportedCustomBubblingEventTypeConstants => _exportedCustomBubblingEventTypeConstants ?? (_exportedCustomBubblingEventTypeConstants = GetExportedCustomBubblingEventTypeConstants());
|
||||
private IReadOnlyDictionary<string, object> _exportedCustomBubblingEventTypeConstants;
|
||||
|
||||
public virtual IReadOnlyDictionary<string, object> ExportedCustomDirectEventTypeConstants => _exportedCustomDirectEventTypeConstants ?? (_exportedCustomDirectEventTypeConstants = GetExportedDirectEventTypeConstants());
|
||||
private IReadOnlyDictionary<string, object> _exportedCustomDirectEventTypeConstants;
|
||||
|
||||
private IReadOnlyDictionary<string, object> GetExportedCustomBubblingEventTypeConstants()
|
||||
{
|
||||
var typeInfo = GetType().GetTypeInfo();
|
||||
|
||||
|
@ -263,25 +313,151 @@ namespace Microsoft.ReactNative.Managed
|
|||
|
||||
foreach (var fieldInfo in typeInfo.DeclaredFields)
|
||||
{
|
||||
var attribute = fieldInfo.GetCustomAttribute<U>();
|
||||
if (null != attribute)
|
||||
var attribute = fieldInfo.GetCustomAttribute<ViewManagerExportedBubblingEventTypeConstantAttribute>();
|
||||
if (TryMakeBubblingEvent(attribute, fieldInfo, fieldInfo.FieldType, out string key, out object value, out Delegate memberValue))
|
||||
{
|
||||
constants.Add(attribute.Name ?? fieldInfo.Name, fieldInfo.GetValue(this));
|
||||
constants.Add(key, value);
|
||||
fieldInfo.SetValue(this, memberValue);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var propertyInfo in typeInfo.DeclaredProperties)
|
||||
{
|
||||
var attribute = propertyInfo.GetCustomAttribute<U>();
|
||||
if (null != attribute)
|
||||
var attribute = propertyInfo.GetCustomAttribute<ViewManagerExportedBubblingEventTypeConstantAttribute>();
|
||||
if (TryMakeBubblingEvent(attribute, propertyInfo, propertyInfo.PropertyType, out string key, out object value, out Delegate memberValue))
|
||||
{
|
||||
constants.Add(attribute.Name ?? propertyInfo.Name, propertyInfo.GetMethod.Invoke(this, null));
|
||||
constants.Add(key, value);
|
||||
propertyInfo.SetValue(this, memberValue);
|
||||
}
|
||||
}
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
private bool TryMakeBubblingEvent(ViewManagerExportedBubblingEventTypeConstantAttribute attribute, MemberInfo memberInfo, Type memberType, out string constantKey, out object constantValue, out Delegate memberValue)
|
||||
{
|
||||
if (null != attribute && null != memberInfo && TryGetEventDataType(memberType, out Type eventDataType))
|
||||
{
|
||||
var eventName = attribute.EventName ?? "top" + memberInfo.Name;
|
||||
var bubbleName = attribute.BubbleCallbackName ?? "on" + memberInfo.Name;
|
||||
var captureName = attribute.CaptureCallbackName ?? bubbleName + "Capture";
|
||||
|
||||
var registration = new Dictionary<string, object>
|
||||
{
|
||||
{ "phasedRegistrationNames", new Dictionary<string, object>()
|
||||
{
|
||||
{ "bubbled", bubbleName },
|
||||
{ "captured", captureName },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
constantKey = eventName;
|
||||
constantValue = registration;
|
||||
memberValue = MakeEventDelegate(eventName, memberType, eventDataType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constantKey = default;
|
||||
constantValue = default;
|
||||
memberValue = default;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private IReadOnlyDictionary<string, object> GetExportedDirectEventTypeConstants()
|
||||
{
|
||||
var typeInfo = GetType().GetTypeInfo();
|
||||
|
||||
var constants = new Dictionary<string, object>();
|
||||
|
||||
foreach (var fieldInfo in typeInfo.DeclaredFields)
|
||||
{
|
||||
var attribute = fieldInfo.GetCustomAttribute<ViewManagerExportedDirectEventTypeConstantAttribute>();
|
||||
if (TryMakeDirectEvent(attribute, fieldInfo, fieldInfo.FieldType, out string key, out object value, out Delegate memberValue))
|
||||
{
|
||||
constants.Add(key, value);
|
||||
fieldInfo.SetValue(this, memberValue);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var propertyInfo in typeInfo.DeclaredProperties)
|
||||
{
|
||||
var attribute = propertyInfo.GetCustomAttribute<ViewManagerExportedDirectEventTypeConstantAttribute>();
|
||||
if (TryMakeDirectEvent(attribute, propertyInfo, propertyInfo.PropertyType, out string key, out object value, out Delegate memberValue))
|
||||
{
|
||||
constants.Add(key, value);
|
||||
propertyInfo.SetValue(this, memberValue);
|
||||
}
|
||||
}
|
||||
|
||||
return constants;
|
||||
}
|
||||
|
||||
private bool TryMakeDirectEvent(ViewManagerExportedDirectEventTypeConstantAttribute attribute, MemberInfo memberInfo, Type memberType, out string constantKey, out object constantValue, out Delegate memberValue)
|
||||
{
|
||||
if (null != attribute && null != memberInfo && TryGetEventDataType(memberType, out Type eventDataType))
|
||||
{
|
||||
var eventName = attribute.EventName ?? "top" + memberInfo.Name;
|
||||
var callbackName = attribute.CallbackName ?? "on" + memberInfo.Name;
|
||||
|
||||
var registration = new Dictionary<string, object>
|
||||
{
|
||||
{ "registrationName", callbackName }
|
||||
};
|
||||
|
||||
constantKey = eventName;
|
||||
constantValue = registration;
|
||||
memberValue = MakeEventDelegate(eventName, memberType, eventDataType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constantKey = default;
|
||||
constantValue = default;
|
||||
memberValue = default;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetEventDataType(Type eventType, out Type eventDataType)
|
||||
{
|
||||
if (null != eventType && typeof(Delegate).IsAssignableFrom(eventType))
|
||||
{
|
||||
var eventDelegateMethod = eventType.GetMethod("Invoke");
|
||||
ParameterInfo[] parameters = eventDelegateMethod.GetParameters();
|
||||
|
||||
if (parameters.Length == 2 && parameters[0].ParameterType == typeof(TFrameworkElement))
|
||||
{
|
||||
eventDataType = parameters[1].ParameterType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
eventDataType = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private Delegate MakeEventDelegate(string eventName, Type memberType, Type eventDataType)
|
||||
{
|
||||
//
|
||||
// (TFrameworkElement view, TEventData eventData) =>
|
||||
// {
|
||||
// ReactContext.DispatchEvent(view, eventName, eventData);
|
||||
// };
|
||||
//
|
||||
|
||||
ParameterExpression viewParameter = Expression.Parameter(typeof(TFrameworkElement), "view");
|
||||
ParameterExpression eventDataParameter = Expression.Parameter(eventDataType, "eventData");
|
||||
|
||||
MemberExpression thisReactContext = Expression.Property(Expression.Constant(this), "ReactContext");
|
||||
|
||||
MethodCallExpression body = Expression.Call(thisReactContext, typeof(IReactContext).GetMethod("DispatchEvent"), viewParameter, Expression.Constant(eventName, typeof(string)), eventDataParameter);
|
||||
|
||||
return Expression.Lambda(memberType, body, viewParameter, eventDataParameter).Compile();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,5 +27,6 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)ReactPackageBuilderExtensions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ReactSyncMethodInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewManagerAttributes.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ViewManagerEvent.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -30,7 +30,14 @@ namespace Microsoft.ReactNative.Managed
|
|||
{
|
||||
if (!typeInfo.IsAbstract && typeInfo.ImplementedInterfaces.Contains(typeof(IViewManager)))
|
||||
{
|
||||
packageBuilder.AddViewManager(typeInfo.Name, () => (IViewManager)Activator.CreateInstance(typeInfo.AsType()));
|
||||
if (typeInfo.DeclaredConstructors.Any(cInfo => cInfo.GetParameters().Length == 1 && cInfo.GetParameters()[0].ParameterType == typeof(IReactContext)))
|
||||
{
|
||||
packageBuilder.AddViewManager(typeInfo.Name, (reactContext) => (IViewManager)Activator.CreateInstance(typeInfo.AsType(), reactContext));
|
||||
}
|
||||
else if (typeInfo.DeclaredConstructors.Any(cInfo => cInfo.GetParameters().Length == 0))
|
||||
{
|
||||
packageBuilder.AddViewManager(typeInfo.Name, (reactContext) => (IViewManager)Activator.CreateInstance(typeInfo.AsType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,54 +7,87 @@ using Microsoft.ReactNative.Bridge;
|
|||
|
||||
namespace Microsoft.ReactNative.Managed
|
||||
{
|
||||
|
||||
internal abstract class ViewManagerNamedAttribute : Attribute
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
internal class ViewManagerExportedViewConstantAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string ConstantName { get; set; }
|
||||
|
||||
public ViewManagerNamedAttribute() : base() { }
|
||||
public ViewManagerExportedViewConstantAttribute() : base() { }
|
||||
|
||||
public ViewManagerNamedAttribute(string name)
|
||||
public ViewManagerExportedViewConstantAttribute(string constantName)
|
||||
{
|
||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
ConstantName = constantName ?? throw new ArgumentNullException(nameof(constantName));
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
internal class ViewManagerPropertyAttribute : Attribute
|
||||
{
|
||||
public string PropertyName { get; set; }
|
||||
|
||||
public ViewManagerPropertyType? PropertyType { get; set; } = null;
|
||||
|
||||
public ViewManagerPropertyAttribute() : base() { }
|
||||
|
||||
public ViewManagerPropertyAttribute(string propertyName)
|
||||
{
|
||||
PropertyName = propertyName ?? throw new ArgumentNullException(nameof(propertyName));
|
||||
}
|
||||
|
||||
public ViewManagerPropertyAttribute(string propertyName, ViewManagerPropertyType type) : this(propertyName)
|
||||
{
|
||||
PropertyType = type;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
internal class ViewManagerCommandAttribute : Attribute
|
||||
{
|
||||
public string CommandName { get; set; }
|
||||
|
||||
public ViewManagerCommandAttribute() : base() { }
|
||||
|
||||
public ViewManagerCommandAttribute(string commandName)
|
||||
{
|
||||
CommandName = commandName ?? throw new ArgumentNullException(nameof(commandName));
|
||||
}
|
||||
}
|
||||
|
||||
internal class ViewManagerExportedDirectEventTypeConstantAttribute : Attribute
|
||||
{
|
||||
public string EventName { get; private set; }
|
||||
|
||||
public string CallbackName { get; private set; }
|
||||
|
||||
public ViewManagerExportedDirectEventTypeConstantAttribute() : base() { }
|
||||
|
||||
public ViewManagerExportedDirectEventTypeConstantAttribute(string eventName, string callbackName)
|
||||
{
|
||||
EventName = eventName ?? throw new ArgumentNullException(nameof(eventName));
|
||||
CallbackName = callbackName ?? throw new ArgumentNullException(nameof(callbackName));
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
internal class ViewManagerExportedViewConstantAttribute : ViewManagerNamedAttribute
|
||||
internal class ViewManagerExportedBubblingEventTypeConstantAttribute : Attribute
|
||||
{
|
||||
public ViewManagerExportedViewConstantAttribute() : base() { }
|
||||
public string EventName { get; private set; }
|
||||
|
||||
public ViewManagerExportedViewConstantAttribute(string name) : base(name) { }
|
||||
}
|
||||
public string BubbleCallbackName { get; private set; }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
internal class ViewManagerPropertyAttribute : ViewManagerNamedAttribute
|
||||
{
|
||||
public ViewManagerPropertyType? Type { get; set; } = null;
|
||||
public string CaptureCallbackName { get; private set; }
|
||||
|
||||
public ViewManagerPropertyAttribute() : base() { }
|
||||
public ViewManagerExportedBubblingEventTypeConstantAttribute() : base() { }
|
||||
|
||||
public ViewManagerPropertyAttribute(string name) : base(name) { }
|
||||
|
||||
public ViewManagerPropertyAttribute(string name, ViewManagerPropertyType type) : this(name)
|
||||
public ViewManagerExportedBubblingEventTypeConstantAttribute(string eventName, string bubbleCallbackName)
|
||||
{
|
||||
Type = type;
|
||||
EventName = eventName ?? throw new ArgumentNullException(nameof(eventName));
|
||||
BubbleCallbackName = bubbleCallbackName ?? throw new ArgumentNullException(nameof(bubbleCallbackName));
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
internal class ViewManagerCommandAttribute : ViewManagerNamedAttribute
|
||||
{
|
||||
public long? CommandId { get; set; }
|
||||
|
||||
public ViewManagerCommandAttribute() : base() { }
|
||||
|
||||
public ViewManagerCommandAttribute(string name) : base(name) { }
|
||||
|
||||
public ViewManagerCommandAttribute(string name, long commandId) : this(name)
|
||||
public ViewManagerExportedBubblingEventTypeConstantAttribute(string eventName, string bubbleCallbackName, string captureCallbackName) : this(eventName, bubbleCallbackName)
|
||||
{
|
||||
CommandId = commandId;
|
||||
CaptureCallbackName = captureCallbackName ?? throw new ArgumentNullException(nameof(captureCallbackName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using Windows.UI.Xaml;
|
||||
|
||||
namespace Microsoft.ReactNative.Managed
|
||||
{
|
||||
internal delegate void ViewManagerEvent<TFrameworkElement, TEventData>(TFrameworkElement view, TEventData eventData) where TFrameworkElement : FrameworkElement;
|
||||
}
|
|
@ -17,6 +17,7 @@ ABIViewManager::ABIViewManager(
|
|||
m_viewManagerWithExportedViewConstants{viewManager.try_as<IViewManagerWithExportedViewConstants>()},
|
||||
m_viewManagerWithNativeProperties{viewManager.try_as<IViewManagerWithNativeProperties>()},
|
||||
m_viewManagerWithCommands{viewManager.try_as<IViewManagerWithCommands>()},
|
||||
m_viewManagerWithExportedEventTypeConstants{viewManager.try_as<IViewManagerWithExportedEventTypeConstants>()},
|
||||
m_name{to_string(viewManager.Name())} {
|
||||
if (m_viewManagerWithNativeProperties) {
|
||||
m_nativeProps = m_viewManagerWithNativeProperties.NativeProps();
|
||||
|
@ -151,4 +152,34 @@ void ABIViewManager::DispatchCommand(
|
|||
}
|
||||
}
|
||||
|
||||
folly::dynamic ABIViewManager::GetExportedCustomBubblingEventTypeConstants() const {
|
||||
folly::dynamic parent = Super::GetExportedCustomBubblingEventTypeConstants();
|
||||
|
||||
if (m_viewManagerWithExportedEventTypeConstants) {
|
||||
auto outerChild = m_viewManagerWithExportedEventTypeConstants.ExportedCustomBubblingEventTypeConstants();
|
||||
for (const auto &pair : outerChild) {
|
||||
std::string key = to_string(pair.Key());
|
||||
folly::dynamic value = ConvertToDynamic(pair.Value());
|
||||
parent.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
folly::dynamic ABIViewManager::GetExportedCustomDirectEventTypeConstants() const {
|
||||
folly::dynamic parent = Super::GetExportedCustomDirectEventTypeConstants();
|
||||
|
||||
if (m_viewManagerWithExportedEventTypeConstants) {
|
||||
auto outerChild = m_viewManagerWithExportedEventTypeConstants.ExportedCustomDirectEventTypeConstants();
|
||||
for (const auto &pair : outerChild) {
|
||||
std::string key = to_string(pair.Key());
|
||||
folly::dynamic value = ConvertToDynamic(pair.Value());
|
||||
parent.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
} // namespace winrt::Microsoft::ReactNative::Bridge
|
||||
|
|
|
@ -43,6 +43,10 @@ class ABIViewManager : public react::uwp::FrameworkElementViewManager {
|
|||
int64_t commandId,
|
||||
const folly::dynamic &commandArgs) override;
|
||||
|
||||
folly::dynamic GetExportedCustomBubblingEventTypeConstants() const override;
|
||||
|
||||
folly::dynamic GetExportedCustomDirectEventTypeConstants() const override;
|
||||
|
||||
protected:
|
||||
winrt::Windows::UI::Xaml::DependencyObject CreateViewCore(int64_t) override;
|
||||
|
||||
|
@ -51,6 +55,8 @@ class ABIViewManager : public react::uwp::FrameworkElementViewManager {
|
|||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithExportedViewConstants m_viewManagerWithExportedViewConstants;
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithNativeProperties m_viewManagerWithNativeProperties;
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithCommands m_viewManagerWithCommands;
|
||||
winrt::Microsoft::ReactNative::Bridge::IViewManagerWithExportedEventTypeConstants
|
||||
m_viewManagerWithExportedEventTypeConstants;
|
||||
|
||||
winrt::Windows::Foundation::Collections::IMapView<winrt::hstring, ViewManagerPropertyType> m_nativeProps;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "pch.h"
|
||||
#include "IReactContext.h"
|
||||
|
||||
#include "ReactSupport.h"
|
||||
|
||||
namespace winrt::Microsoft::ReactNative::Bridge {
|
||||
|
||||
void ReactContext::DispatchEvent(
|
||||
winrt::Windows::UI::Xaml::FrameworkElement const &view,
|
||||
hstring const &eventName,
|
||||
IInspectable const &eventData) noexcept {
|
||||
if (auto instance = m_instance.lock()) {
|
||||
instance->DispatchEvent(unbox_value<int64_t>(view.Tag()), to_string(eventName), ConvertToDynamic(eventData));
|
||||
}
|
||||
}
|
||||
|
||||
void ReactContext::CallJsFunction(
|
||||
hstring const &moduleName,
|
||||
hstring const &method,
|
||||
IInspectable const ¶ms) noexcept {
|
||||
if (auto instance = m_instance.lock()) {
|
||||
instance->CallJsFunction(to_string(moduleName), to_string(method), ConvertToDynamic(params));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace winrt::Microsoft::ReactNative::Bridge
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ReactUWP/IReactInstance.h>
|
||||
|
||||
#include "winrt/Microsoft.ReactNative.Bridge.h"
|
||||
|
||||
namespace winrt::Microsoft::ReactNative::Bridge {
|
||||
|
||||
struct ReactContext : winrt::implements<ReactContext, IReactContext> {
|
||||
ReactContext(std::weak_ptr<react::uwp::IReactInstance> instance) noexcept : m_instance(instance) {}
|
||||
|
||||
public: // IReactContext
|
||||
void DispatchEvent(
|
||||
winrt::Windows::UI::Xaml::FrameworkElement const &view,
|
||||
hstring const &eventName,
|
||||
IInspectable const &eventData) noexcept;
|
||||
void CallJsFunction(hstring const &moduleName, hstring const &method, IInspectable const ¶ms) noexcept;
|
||||
|
||||
private:
|
||||
std::weak_ptr<react::uwp::IReactInstance> m_instance;
|
||||
};
|
||||
|
||||
} // namespace winrt::Microsoft::ReactNative::Bridge
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
namespace Microsoft.ReactNative.Bridge
|
||||
{
|
||||
[webhosthidden]
|
||||
interface IReactContext
|
||||
{
|
||||
void DispatchEvent(Windows.UI.Xaml.FrameworkElement view, String eventName, IInspectable eventData);
|
||||
void CallJsFunction(String moduleName, String method, IInspectable params);
|
||||
};
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import "IReactContext.idl";
|
||||
import "IReactModuleBuilder.idl";
|
||||
import "IViewManager.idl";
|
||||
|
||||
namespace Microsoft.ReactNative.Bridge {
|
||||
|
||||
delegate Object ReactModuleProvider(IReactModuleBuilder moduleBuilder);
|
||||
delegate IViewManager ReactViewManagerProvider();
|
||||
delegate IViewManager ReactViewManagerProvider(IReactContext reactContext);
|
||||
|
||||
interface IReactPackageBuilder {
|
||||
// TODO: Add message thread argument
|
||||
|
|
|
@ -43,4 +43,12 @@ namespace Microsoft.ReactNative.Bridge
|
|||
|
||||
void DispatchCommand(Windows.UI.Xaml.FrameworkElement view, Int64 commandId, Windows.Foundation.Collections.IVectorView<IInspectable> commandArgs);
|
||||
};
|
||||
|
||||
[webhosthidden]
|
||||
interface IViewManagerWithExportedEventTypeConstants
|
||||
{
|
||||
Windows.Foundation.Collections.IMapView<String, IInspectable> ExportedCustomBubblingEventTypeConstants { get; };
|
||||
|
||||
Windows.Foundation.Collections.IMapView<String, IInspectable> ExportedCustomDirectEventTypeConstants { get; };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -128,8 +128,8 @@
|
|||
<DependentUpon>ReactApplicationDelegate.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReactContext.h">
|
||||
<DependentUpon>ReactContext.idl</DependentUpon>
|
||||
<ClInclude Include="IReactContext.h">
|
||||
<DependentUpon>IReactContext.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReactInstanceCreator.h" />
|
||||
|
@ -184,8 +184,8 @@
|
|||
<DependentUpon>ReactApplicationDelegate.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ReactContext.cpp">
|
||||
<DependentUpon>ReactContext.idl</DependentUpon>
|
||||
<ClCompile Include="IReactContext.cpp">
|
||||
<DependentUpon>IReactContext.idl</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ReactInstanceCreator.cpp" />
|
||||
|
@ -229,7 +229,7 @@
|
|||
<Midl Include="ReactApplicationDelegate.idl">
|
||||
<SubType>Designer</SubType>
|
||||
</Midl>
|
||||
<Midl Include="ReactContext.idl">
|
||||
<Midl Include="IReactContext.idl">
|
||||
<SubType>Designer</SubType>
|
||||
</Midl>
|
||||
<Midl Include="ReactInstance.idl">
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "pch.h"
|
||||
#include "ReactContext.h"
|
||||
#if __has_include("Bridge.ReactContext.g.cpp")
|
||||
#include "Bridge.ReactContext.g.cpp"
|
||||
#endif
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Microsoft::ReactNative::Bridge;
|
||||
using namespace Windows::Foundation::Collections;
|
||||
|
||||
namespace winrt::Microsoft::ReactNative::Bridge::implementation {
|
||||
IReactInstance ReactContext::ReactInstance() {
|
||||
if (m_reactInstance == nullptr) {
|
||||
throw hresult_invalid_operation(L"ReactInstance has not yet been set.");
|
||||
}
|
||||
|
||||
return m_reactInstance;
|
||||
}
|
||||
|
||||
void ReactContext::InitializeWithInstance(Bridge::ReactInstance const &instance) {
|
||||
if (instance == nullptr) {
|
||||
throw hresult_null_argument(L"instance");
|
||||
}
|
||||
|
||||
if (m_reactInstance != nullptr) {
|
||||
throw hresult_invalid_argument(L"ReactInstance has already been set.");
|
||||
}
|
||||
m_reactInstance = instance;
|
||||
}
|
||||
|
||||
void ReactContext::CallJSFunction(
|
||||
hstring const &moduleName,
|
||||
hstring const &method,
|
||||
IVectorView<IInspectable> const ¶ms) {
|
||||
if (m_reactInstance == nullptr) {
|
||||
ReactInstance().InvokeFunction(moduleName, method, params);
|
||||
}
|
||||
}
|
||||
} // namespace winrt::Microsoft::ReactNative::Bridge::implementation
|
|
@ -1,29 +0,0 @@
|
|||
#pragma once
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "Bridge.ReactContext.g.h"
|
||||
|
||||
#include "ReactInstance.h"
|
||||
|
||||
using namespace winrt;
|
||||
using namespace Windows::Foundation::Collections;
|
||||
|
||||
namespace winrt::Microsoft::ReactNative::Bridge::implementation {
|
||||
struct ReactContext : ReactContextT<ReactContext> {
|
||||
ReactContext() = default;
|
||||
|
||||
IReactInstance ReactInstance();
|
||||
|
||||
void InitializeWithInstance(Bridge::ReactInstance const &instance);
|
||||
|
||||
void CallJSFunction(hstring const &moduleName, hstring const &method, IVectorView<IInspectable> const ¶ms);
|
||||
|
||||
private:
|
||||
Bridge::ReactInstance m_reactInstance{nullptr};
|
||||
};
|
||||
} // namespace winrt::Microsoft::ReactNative::Bridge::implementation
|
||||
|
||||
namespace winrt::Microsoft::ReactNative::Bridge::factory_implementation {
|
||||
struct ReactContext : ReactContextT<ReactContext, implementation::ReactContext> {};
|
||||
} // namespace winrt::Microsoft::ReactNative::Bridge::factory_implementation
|
|
@ -1,22 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import "ReactInstance.idl";
|
||||
|
||||
namespace Microsoft.ReactNative.Bridge
|
||||
{
|
||||
[webhosthidden]
|
||||
runtimeclass ReactContext
|
||||
{
|
||||
ReactContext();
|
||||
IReactInstance ReactInstance { get; };
|
||||
|
||||
// TODO: Look at supporting this functionality as used by modules
|
||||
/*
|
||||
void AddLifecycleEventListener(ILifecycleEventListener listener);
|
||||
void RemoveLifecycleEventListener(ILifecycleEventListener listener);
|
||||
void AddBackgroundEventListener(IBackgroundEventListener listener);
|
||||
void RemoveBackgroundEventListener(IBackgroundEventListener listener);
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -121,7 +121,7 @@ std::shared_ptr<react::uwp::IReactInstanceCreator> ReactInstanceManager::Instanc
|
|||
return m_reactInstanceCreator;
|
||||
}
|
||||
|
||||
auto ReactInstanceManager::GetOrCreateReactContextAsync() -> IAsyncOperation<ReactContext> {
|
||||
auto ReactInstanceManager::GetOrCreateReactContextAsync() -> IAsyncOperation<IReactContext> {
|
||||
if (m_currentReactContext != nullptr)
|
||||
co_return m_currentReactContext;
|
||||
|
||||
|
@ -132,9 +132,7 @@ auto ReactInstanceManager::GetOrCreateReactContextAsync() -> IAsyncOperation<Rea
|
|||
|
||||
// TODO: Should we make this method async? On first run when getInstance
|
||||
// is called it starts things up. Does this need to block?
|
||||
auto ReactInstanceManager::CreateReactContextCoreAsync() -> IAsyncOperation<ReactContext> {
|
||||
auto reactContext = ReactContext();
|
||||
|
||||
auto ReactInstanceManager::CreateReactContextCoreAsync() -> IAsyncOperation<IReactContext> {
|
||||
/* TODO hook up an exception handler if UseDeveloperSupport is set
|
||||
if (m_useDeveloperSupport) {
|
||||
if (m_nativeModuleCallExceptionHandler) {
|
||||
|
@ -175,11 +173,10 @@ auto ReactInstanceManager::CreateReactContextCoreAsync() -> IAsyncOperation<Reac
|
|||
// TODO: Could access to the module registry be easier if the ReactInstance
|
||||
// implementation were lifted up into this project.
|
||||
|
||||
auto instancePtr = InstanceCreator()->getInstance();
|
||||
auto reactInstance = winrt::make<Bridge::implementation::ReactInstance>(instancePtr);
|
||||
auto reactInstance = InstanceCreator()->getInstance();
|
||||
|
||||
Bridge::implementation::ReactContext *contextImpl{get_self<Bridge::implementation::ReactContext>(reactContext)};
|
||||
contextImpl->InitializeWithInstance(reactInstance);
|
||||
auto reactContext =
|
||||
winrt::make<winrt::Microsoft::ReactNative::Bridge::ReactContext>(reactInstance).as<IReactContext>();
|
||||
|
||||
// TODO: Investigate whether we need the equivalent of the
|
||||
// LimitedConcurrencyActionQueue from the C# implementation that is used to
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
#include "ReactInstanceManager.g.h"
|
||||
|
||||
#include "IReactContext.h"
|
||||
#include "LifecycleState.h"
|
||||
#include "NativeModulesProvider.h"
|
||||
#include "ReactContext.h"
|
||||
#include "ReactInstanceSettings.h"
|
||||
#include "ViewManagersProvider.h"
|
||||
|
||||
|
@ -30,8 +30,8 @@ struct ReactInstanceManager : ReactInstanceManagerT<ReactInstanceManager> {
|
|||
bool useDeveloperSupport,
|
||||
LifecycleState initialLifecycleState);
|
||||
|
||||
IAsyncOperation<ReactContext> GetOrCreateReactContextAsync();
|
||||
ReactContext CurrentReactContext() {
|
||||
IAsyncOperation<IReactContext> GetOrCreateReactContextAsync();
|
||||
IReactContext CurrentReactContext() {
|
||||
return m_currentReactContext;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ struct ReactInstanceManager : ReactInstanceManagerT<ReactInstanceManager> {
|
|||
void OnBackPressed();
|
||||
|
||||
private:
|
||||
ReactContext m_currentReactContext{nullptr};
|
||||
IReactContext m_currentReactContext{nullptr};
|
||||
Microsoft::ReactNative::ReactInstanceSettings m_instanceSettings{nullptr};
|
||||
std::string m_jsBundleFile{};
|
||||
std::string m_jsMainModuleName{};
|
||||
|
@ -66,7 +66,7 @@ struct ReactInstanceManager : ReactInstanceManagerT<ReactInstanceManager> {
|
|||
// instances on live reload.
|
||||
std::shared_ptr<react::uwp::IReactInstanceCreator> m_reactInstanceCreator{nullptr};
|
||||
|
||||
IAsyncOperation<ReactContext> CreateReactContextCoreAsync();
|
||||
IAsyncOperation<IReactContext> CreateReactContextCoreAsync();
|
||||
};
|
||||
} // namespace winrt::Microsoft::ReactNative::implementation
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT License.
|
||||
|
||||
import "ReactNativeHost.idl";
|
||||
import "ReactContext.idl";
|
||||
import "IReactContext.idl";
|
||||
|
||||
namespace Microsoft.ReactNative
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ namespace Microsoft.ReactNative
|
|||
runtimeclass ReactInstanceManager
|
||||
{
|
||||
ReactInstanceManager();
|
||||
Microsoft.ReactNative.Bridge.ReactContext CurrentReactContext();
|
||||
Microsoft.ReactNative.Bridge.IReactContext CurrentReactContext();
|
||||
void OnSuspend();
|
||||
void OnEnteredBackground();
|
||||
void OnLeavingBackground();
|
||||
|
|
|
@ -12,6 +12,14 @@ folly::dynamic ConvertToDynamic(IInspectable const &object) {
|
|||
if (object == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (auto const &map = object.try_as<IMapView<hstring, IInspectable>>()) {
|
||||
folly::dynamic obj = folly::dynamic::object;
|
||||
for (auto const &kvp : map) {
|
||||
obj[to_string(kvp.Key())] = ConvertToDynamic(kvp.Value());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
auto propValue = object.try_as<IPropertyValue>();
|
||||
if (!propValue) {
|
||||
auto stringable = object.try_as<IStringable>();
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "pch.h"
|
||||
#include "ViewManagersProvider.h"
|
||||
|
||||
#include "IReactContext.h"
|
||||
|
||||
#include "ABIViewManager.h"
|
||||
|
||||
namespace winrt::Microsoft::ReactNative::Bridge {
|
||||
|
@ -17,7 +19,8 @@ std::vector<react::uwp::NativeViewManager> ViewManagersProvider::GetViewManagers
|
|||
for (auto &entry : m_viewManagerProviders) {
|
||||
auto viewManagerProvider = entry.second;
|
||||
|
||||
auto viewManager = std::make_unique<ABIViewManager>(instance, viewManagerProvider());
|
||||
auto reactContext = winrt::make<ReactContext>(instance).as<IReactContext>();
|
||||
auto viewManager = std::make_unique<ABIViewManager>(instance, viewManagerProvider(reactContext));
|
||||
|
||||
viewManagers.emplace_back(std::move(viewManager));
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче