diff --git a/change/react-native-windows-2020-05-28-08-10-23-elementFromTag.json b/change/react-native-windows-2020-05-28-08-10-23-elementFromTag.json new file mode 100644 index 00000000000..936887b8c89 --- /dev/null +++ b/change/react-native-windows-2020-05-28-08-10-23-elementFromTag.json @@ -0,0 +1,8 @@ +{ + "type": "prerelease", + "comment": "Add XamlUIService with ElementFromReactTag", + "packageName": "react-native-windows", + "email": "acoates@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-05-28T15:10:23.674Z" +} diff --git a/vnext/Microsoft.ReactNative/IReactContext.cpp b/vnext/Microsoft.ReactNative/IReactContext.cpp index 295293a601c..5acc4ff36a7 100644 --- a/vnext/Microsoft.ReactNative/IReactContext.cpp +++ b/vnext/Microsoft.ReactNative/IReactContext.cpp @@ -4,6 +4,7 @@ #include "pch.h" #include "IReactContext.h" #include "DynamicWriter.h" +#include "XamlUIService.h" namespace winrt::Microsoft::ReactNative::implementation { @@ -17,18 +18,18 @@ IReactDispatcher ReactContext::UIDispatcher() noexcept { return Properties().Get(ReactDispatcherHelper::UIDispatcherProperty()).try_as(); } +// Deprecated: Use XamlUIService directly. void ReactContext::DispatchEvent( winrt::Windows::UI::Xaml::FrameworkElement const &view, hstring const &eventName, JSValueArgWriter const &eventDataArgWriter) noexcept { - folly::dynamic eventData; // default to NULLT - if (eventDataArgWriter != nullptr) { - auto eventDataWriter = winrt::make_self(); - eventDataArgWriter(*eventDataWriter); - eventData = eventDataWriter->TakeValue(); - } + auto xamlUIService = Properties() + .Get(XamlUIService::XamlUIServiceProperty().Handle()) + .try_as(); - m_context->DispatchEvent(unbox_value(view.Tag()), to_string(eventName), std::move(eventData)); + if (xamlUIService) { + xamlUIService.DispatchEvent(view, eventName, eventDataArgWriter); + } } void ReactContext::CallJSFunction( diff --git a/vnext/Microsoft.ReactNative/IReactContext.idl b/vnext/Microsoft.ReactNative/IReactContext.idl index 43b684a1595..e186d0f15c8 100644 --- a/vnext/Microsoft.ReactNative/IReactContext.idl +++ b/vnext/Microsoft.ReactNative/IReactContext.idl @@ -10,10 +10,13 @@ namespace Microsoft.ReactNative { [webhosthidden] interface IReactContext { IReactPropertyBag Properties { get; }; - void DispatchEvent(Windows.UI.Xaml.FrameworkElement view, String eventName, JSValueArgWriter eventDataArgWriter); // Get ReactDispatcherHelper::UIDispatcherProperty from the Properties property bag. IReactDispatcher UIDispatcher { get; }; + // Deprecated: Use DispatchEvent on XamlUIService instead + void DispatchEvent(Windows.UI.Xaml.FrameworkElement view, String eventName, JSValueArgWriter eventDataArgWriter); + + // Call JavaScript function methodName of moduleName. void CallJSFunction(String moduleName, String methodName, JSValueArgWriter paramsArgWriter); void EmitJSEvent(String eventEmitterName, String eventName, JSValueArgWriter paramsArgWriter); } diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj index 63df532eedf..fdf867502ea 100644 --- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj @@ -326,6 +326,10 @@ ReactNativeHost.idl Code + + XamlUIService.idl + Code + IReactPackageBuilder.idl @@ -493,6 +497,10 @@ ReactNativeHost.idl Code + + XamlUIService.idl + Code + IReactPackageBuilder.idl @@ -552,6 +560,9 @@ Designer + + Designer + Designer diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters index 890b5e7f36e..eb899f260e3 100644 --- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters @@ -706,6 +706,7 @@ + diff --git a/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp b/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp index aa3b22f86b9..49e4ccf380e 100644 --- a/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +++ b/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "ReactErrorProvider.h" #include "Microsoft.ReactNative/Threading/MessageQueueThreadFactory.h" @@ -481,6 +482,10 @@ void ReactInstanceWin::InitUIManager() noexcept { react::uwp::AddPolyesterViewManagers(viewManagers, m_legacyReactInstance); auto uiManager = react::uwp::CreateUIManager2(std::move(viewManagers)); + auto wkUIManger = std::weak_ptr(uiManager); + m_reactContext->Properties().Set( + winrt::Microsoft::ReactNative::implementation::XamlUIService::XamlUIServiceProperty().Handle(), + winrt::make(std::move(wkUIManger), m_reactContext)); m_uiManager.Exchange(std::move(uiManager)); } diff --git a/vnext/Microsoft.ReactNative/XamlUIService.cpp b/vnext/Microsoft.ReactNative/XamlUIService.cpp new file mode 100644 index 00000000000..4456df32d19 --- /dev/null +++ b/vnext/Microsoft.ReactNative/XamlUIService.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "pch.h" +#include "XamlUIService.h" +#include "XamlUIService.g.cpp" +#include "DynamicWriter.h" +#include "Views/ShadowNodeBase.h" + +namespace winrt::Microsoft::ReactNative::implementation { + +XamlUIService::XamlUIService( + std::weak_ptr &&uimanager, + Mso::CntPtr &&context) noexcept + : m_wkUIManager(uimanager), m_context(context) {} + +winrt::Windows::UI::Xaml::DependencyObject XamlUIService::ElementFromReactTag(int64_t reactTag) noexcept { + if (auto strongUIManager = m_wkUIManager.lock()) { + auto shadowNode = strongUIManager->FindShadowNodeForTag(reactTag); + if (!shadowNode) + return nullptr; + + return static_cast(shadowNode)->GetView(); + } + return nullptr; +} + +/*static*/ winrt::Microsoft::ReactNative::XamlUIService XamlUIService::FromContext(IReactContext context) { + return context.Properties() + .Get(XamlUIService::XamlUIServiceProperty().Handle()) + .try_as(); +} + +void XamlUIService::DispatchEvent( + winrt::Windows::UI::Xaml::FrameworkElement const &view, + hstring const &eventName, + JSValueArgWriter const &eventDataArgWriter) noexcept { + folly::dynamic eventData; // default to NULLT + if (eventDataArgWriter != nullptr) { + auto eventDataWriter = winrt::make_self(); + eventDataArgWriter(*eventDataWriter); + eventData = eventDataWriter->TakeValue(); + } + + m_context->DispatchEvent(unbox_value(view.Tag()), to_string(eventName), std::move(eventData)); +} + +/*static*/ ReactPropertyId XamlUIService::XamlUIServiceProperty() noexcept { + static ReactPropertyId uiManagerProperty{L"ReactNative.UIManager", L"XamlUIManager"}; + return uiManagerProperty; +} + +} // namespace winrt::Microsoft::ReactNative::implementation diff --git a/vnext/Microsoft.ReactNative/XamlUIService.h b/vnext/Microsoft.ReactNative/XamlUIService.h new file mode 100644 index 00000000000..2d6737f18b1 --- /dev/null +++ b/vnext/Microsoft.ReactNative/XamlUIService.h @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#include "XamlUIService.g.h" +#include "IUIManager.h" + +#include "ReactHost/React.h" +#include "ReactPropertyBag.h" +#include "winrt/Microsoft.ReactNative.h" + +namespace winrt::Microsoft::ReactNative::implementation { + +struct XamlUIService : XamlUIServiceT { + public: + XamlUIService( + std::weak_ptr &&uimanager, + Mso::CntPtr &&context) noexcept; + static ReactPropertyId XamlUIServiceProperty() noexcept; + + winrt::Windows::UI::Xaml::DependencyObject ElementFromReactTag(int64_t reactTag) noexcept; + static winrt::Microsoft::ReactNative::XamlUIService FromContext(IReactContext context); + void DispatchEvent( + winrt::Windows::UI::Xaml::FrameworkElement const &view, + hstring const &eventName, + JSValueArgWriter const &eventDataArgWriter) noexcept; + + private: + std::weak_ptr m_wkUIManager; + Mso::CntPtr m_context; +}; + +} // namespace winrt::Microsoft::ReactNative::implementation + +namespace winrt::Microsoft::ReactNative::factory_implementation { +struct XamlUIService : XamlUIServiceT {}; +} // namespace winrt::Microsoft::ReactNative::factory_implementation diff --git a/vnext/Microsoft.ReactNative/XamlUIService.idl b/vnext/Microsoft.ReactNative/XamlUIService.idl new file mode 100644 index 00000000000..f132acccc35 --- /dev/null +++ b/vnext/Microsoft.ReactNative/XamlUIService.idl @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import "IReactContext.idl"; + +namespace Microsoft.ReactNative { + + [default_interface] + [webhosthidden] + runtimeclass XamlUIService { + static XamlUIService FromContext(IReactContext context); + + Windows.UI.Xaml.DependencyObject ElementFromReactTag(Int64 reactTag); + + // Dispatch UI event. This method is to be moved to IReactViewContext. + void DispatchEvent(Windows.UI.Xaml.FrameworkElement view, String eventName, JSValueArgWriter eventDataArgWriter); + } + +} // namespace Microsoft.ReactNative