From ec16cd8e1f20e986e84b02e0c83102441a889ccc Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 28 Jul 2021 13:05:39 -0400 Subject: [PATCH 1/5] Add root tag to CreateView in ViewManagerBase There are a number of places where a single root view assumption exists in the app. Currently, there is no way to know which root view a Flyout will be shown on, which can be problematic when each root is on a different window. This is the first step to supporting multiple root views. Towards #8250 --- .../Modules/PaperUIManagerModule.cpp | 2 ++ vnext/Microsoft.ReactNative/Views/PaperShadowNode.h | 1 + vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp | 2 +- vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp | 11 +++++++++-- vnext/Microsoft.ReactNative/Views/ViewManagerBase.h | 3 ++- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp b/vnext/Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp index 058305d2a8b..a5a4eaca585 100644 --- a/vnext/Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp +++ b/vnext/Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp @@ -130,6 +130,7 @@ class UIManagerModule : public std::enable_shared_from_this, pu auto node = viewManager->createShadow(); node->m_className = std::move(viewName); node->m_tag = reactTag; + node->m_rootTag = reactTag; node->m_viewManager = viewManager; node->createView(props); @@ -471,6 +472,7 @@ class UIManagerModule : public std::enable_shared_from_this, pu root->m_className = rootClassName; root->m_viewManager = viewManager; root->m_tag = rootViewTag; + root->m_rootTag = rootViewTag; m_nodeRegistry.addRootView(shadow_ptr(root), rootViewTag); m_nativeUIManager->AddRootView(*root, rootView); diff --git a/vnext/Microsoft.ReactNative/Views/PaperShadowNode.h b/vnext/Microsoft.ReactNative/Views/PaperShadowNode.h index 7262a7511e8..1eeea333bfc 100644 --- a/vnext/Microsoft.ReactNative/Views/PaperShadowNode.h +++ b/vnext/Microsoft.ReactNative/Views/PaperShadowNode.h @@ -27,6 +27,7 @@ struct ShadowNode { virtual void createView(const winrt::Microsoft::ReactNative::JSValueObject &props) = 0; int64_t m_tag{0}; + int64_t m_rootTag{0}; std::string m_className; std::vector m_children; int64_t m_parent = -1; diff --git a/vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp b/vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp index 46031a7fa0d..81e49592c5b 100644 --- a/vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp +++ b/vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp @@ -32,7 +32,7 @@ void ShadowNodeBase::updateProperties(winrt::Microsoft::ReactNative::JSValueObje } void ShadowNodeBase::createView(const winrt::Microsoft::ReactNative::JSValueObject &props) { - m_view = GetViewManager()->CreateView(this->m_tag, props); + m_view = GetViewManager()->CreateView(this->m_tag, this->m_rootTag, props); if (g_HasActualSizeProperty == TriBit::Undefined) { if (auto uielement = m_view.try_as()) { diff --git a/vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp b/vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp index 79bd462053d..c6def857631 100644 --- a/vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp +++ b/vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp @@ -193,8 +193,8 @@ void ViewManagerBase::GetExportedCustomDirectEventTypeConstants( } } -XamlView ViewManagerBase::CreateView(int64_t tag, const winrt::Microsoft::ReactNative::JSValueObject &props) { - XamlView view = CreateViewCore(tag, props); +XamlView ViewManagerBase::CreateView(int64_t tag, int64_t rootTag, const winrt::Microsoft::ReactNative::JSValueObject &props) { + XamlView view = CreateViewCore(tag, rootTag, props); OnViewCreated(view); // Set the tag if the element type supports it @@ -252,6 +252,13 @@ void ViewManagerBase::UpdateProperties( OnPropertiesUpdated(nodeToUpdate); } +XamlView ViewManagerBase::CreateViewCore( + int64_t tag, + int64_t rootTag, + const winrt::Microsoft::ReactNative::JSValueObject& props) { + return CreateViewCore(tag, props); +} + bool ViewManagerBase::UpdateProperty( ShadowNodeBase *nodeToUpdate, const std::string &propertyName, diff --git a/vnext/Microsoft.ReactNative/Views/ViewManagerBase.h b/vnext/Microsoft.ReactNative/Views/ViewManagerBase.h index f4fbf6a81d3..5ac7df4d87e 100644 --- a/vnext/Microsoft.ReactNative/Views/ViewManagerBase.h +++ b/vnext/Microsoft.ReactNative/Views/ViewManagerBase.h @@ -39,7 +39,7 @@ class REACTWINDOWS_EXPORT ViewManagerBase : public IViewManager { ViewManagerBase(const Mso::React::IReactContext &context); virtual ~ViewManagerBase() {} - virtual XamlView CreateView(int64_t tag, const winrt::Microsoft::ReactNative::JSValueObject &props); + virtual XamlView CreateView(int64_t tag, int64_t rootTag, const winrt::Microsoft::ReactNative::JSValueObject &props); void GetExportedViewConstants(const winrt::Microsoft::ReactNative::IJSValueWriter &writer) const override; void GetCommands(const winrt::Microsoft::ReactNative::IJSValueWriter &writer) const override; @@ -92,6 +92,7 @@ class REACTWINDOWS_EXPORT ViewManagerBase : public IViewManager { protected: virtual XamlView CreateViewCore(int64_t tag, const winrt::Microsoft::ReactNative::JSValueObject &props) = 0; + virtual XamlView CreateViewCore(int64_t tag, int64_t rootTag, const winrt::Microsoft::ReactNative::JSValueObject &props); virtual void OnViewCreated(XamlView view) {} virtual bool UpdateProperty( ShadowNodeBase *nodeToUpdate, From f4dd0ba73ada6ece64ec320659e2dea11c5efcda Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 28 Jul 2021 13:12:28 -0400 Subject: [PATCH 2/5] Change files --- ...ative-windows-2c2723ef-9489-4c71-b544-b6bb24e74a32.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-2c2723ef-9489-4c71-b544-b6bb24e74a32.json diff --git a/change/react-native-windows-2c2723ef-9489-4c71-b544-b6bb24e74a32.json b/change/react-native-windows-2c2723ef-9489-4c71-b544-b6bb24e74a32.json new file mode 100644 index 00000000000..b0214de87a4 --- /dev/null +++ b/change/react-native-windows-2c2723ef-9489-4c71-b544-b6bb24e74a32.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Add root tag to CreateView in ViewManagerBase", + "packageName": "react-native-windows", + "email": "erozell@outlook.com", + "dependentChangeType": "patch" +} From c603d699c7b6aef6df60f778d12e1bbf448b839e Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 28 Jul 2021 13:20:05 -0400 Subject: [PATCH 3/5] Adds API to get specific XamlRoot to NativeUIManager --- .../Modules/NativeUIManager.cpp | 12 ++++++++++++ .../Microsoft.ReactNative/Modules/NativeUIManager.h | 6 ++++++ vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp | 2 +- .../Microsoft.ReactNative/Views/ViewManagerBase.cpp | 11 ++--------- vnext/Microsoft.ReactNative/Views/ViewManagerBase.h | 3 +-- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp index ab344d43ba6..acbab0df9ab 100644 --- a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp +++ b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp @@ -110,6 +110,18 @@ winrt::XamlRoot NativeUIManager::tryGetXamlRoot() { return nullptr; } +winrt::XamlRoot NativeUIManager::tryGetXamlRoot(int64_t rootTag) { + if (m_host) { + if (auto shadowNode = static_cast(m_host->FindShadowNodeForTag(rootTag))) { + if (auto uiElement10 = shadowNode->GetView().try_as()) { + if (auto xamlRoot = uiElement10.XamlRoot()) + return xamlRoot; + } + } + } + return nullptr; +} + XamlView NativeUIManager::reactPeerOrContainerFrom(xaml::FrameworkElement fe) { if (m_host) { while (fe) { diff --git a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.h b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.h index 108a56cfa4e..4c1c4b68627 100644 --- a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.h +++ b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.h @@ -88,6 +88,12 @@ class NativeUIManager final : public INativeUIManager { // and try to get a valid XamlRoot. xaml::XamlRoot tryGetXamlRoot(); + // For unparented node like Flyout, XamlRoot should be set to handle + // XamlIsland/AppWindow scenarios. Since it doesn't have parent, and all nodes + // in the tree should have the same XamlRoot, this function iterates all roots + // and try to get a valid XamlRoot. + xaml::XamlRoot tryGetXamlRoot(int64_t rootTag); + // Searches itself and its parent to get a valid XamlView. // Like Mouse/Keyboard, the event source may not have matched XamlView. XamlView reactPeerOrContainerFrom(xaml::FrameworkElement fe); diff --git a/vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp b/vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp index 81e49592c5b..46031a7fa0d 100644 --- a/vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp +++ b/vnext/Microsoft.ReactNative/Views/ShadowNodeBase.cpp @@ -32,7 +32,7 @@ void ShadowNodeBase::updateProperties(winrt::Microsoft::ReactNative::JSValueObje } void ShadowNodeBase::createView(const winrt::Microsoft::ReactNative::JSValueObject &props) { - m_view = GetViewManager()->CreateView(this->m_tag, this->m_rootTag, props); + m_view = GetViewManager()->CreateView(this->m_tag, props); if (g_HasActualSizeProperty == TriBit::Undefined) { if (auto uielement = m_view.try_as()) { diff --git a/vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp b/vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp index c6def857631..79bd462053d 100644 --- a/vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp +++ b/vnext/Microsoft.ReactNative/Views/ViewManagerBase.cpp @@ -193,8 +193,8 @@ void ViewManagerBase::GetExportedCustomDirectEventTypeConstants( } } -XamlView ViewManagerBase::CreateView(int64_t tag, int64_t rootTag, const winrt::Microsoft::ReactNative::JSValueObject &props) { - XamlView view = CreateViewCore(tag, rootTag, props); +XamlView ViewManagerBase::CreateView(int64_t tag, const winrt::Microsoft::ReactNative::JSValueObject &props) { + XamlView view = CreateViewCore(tag, props); OnViewCreated(view); // Set the tag if the element type supports it @@ -252,13 +252,6 @@ void ViewManagerBase::UpdateProperties( OnPropertiesUpdated(nodeToUpdate); } -XamlView ViewManagerBase::CreateViewCore( - int64_t tag, - int64_t rootTag, - const winrt::Microsoft::ReactNative::JSValueObject& props) { - return CreateViewCore(tag, props); -} - bool ViewManagerBase::UpdateProperty( ShadowNodeBase *nodeToUpdate, const std::string &propertyName, diff --git a/vnext/Microsoft.ReactNative/Views/ViewManagerBase.h b/vnext/Microsoft.ReactNative/Views/ViewManagerBase.h index 5ac7df4d87e..f4fbf6a81d3 100644 --- a/vnext/Microsoft.ReactNative/Views/ViewManagerBase.h +++ b/vnext/Microsoft.ReactNative/Views/ViewManagerBase.h @@ -39,7 +39,7 @@ class REACTWINDOWS_EXPORT ViewManagerBase : public IViewManager { ViewManagerBase(const Mso::React::IReactContext &context); virtual ~ViewManagerBase() {} - virtual XamlView CreateView(int64_t tag, int64_t rootTag, const winrt::Microsoft::ReactNative::JSValueObject &props); + virtual XamlView CreateView(int64_t tag, const winrt::Microsoft::ReactNative::JSValueObject &props); void GetExportedViewConstants(const winrt::Microsoft::ReactNative::IJSValueWriter &writer) const override; void GetCommands(const winrt::Microsoft::ReactNative::IJSValueWriter &writer) const override; @@ -92,7 +92,6 @@ class REACTWINDOWS_EXPORT ViewManagerBase : public IViewManager { protected: virtual XamlView CreateViewCore(int64_t tag, const winrt::Microsoft::ReactNative::JSValueObject &props) = 0; - virtual XamlView CreateViewCore(int64_t tag, int64_t rootTag, const winrt::Microsoft::ReactNative::JSValueObject &props); virtual void OnViewCreated(XamlView view) {} virtual bool UpdateProperty( ShadowNodeBase *nodeToUpdate, From 685f20e13c21f35cef8cd5f7da223e2e0065431c Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 28 Jul 2021 13:20:33 -0400 Subject: [PATCH 4/5] Get specific XamlRoot for FlyoutViewManager --- vnext/Microsoft.ReactNative/Views/FlyoutViewManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vnext/Microsoft.ReactNative/Views/FlyoutViewManager.cpp b/vnext/Microsoft.ReactNative/Views/FlyoutViewManager.cpp index 949e3834f2c..cd49dfeb42a 100644 --- a/vnext/Microsoft.ReactNative/Views/FlyoutViewManager.cpp +++ b/vnext/Microsoft.ReactNative/Views/FlyoutViewManager.cpp @@ -234,7 +234,7 @@ void FlyoutShadowNode::createView(const winrt::Microsoft::ReactNative::JSValueOb // Set XamlRoot on the Flyout to handle XamlIsland/AppWindow scenarios. if (auto flyoutBase6 = m_flyout.try_as()) { if (auto uiManager = GetNativeUIManager(GetViewManager()->GetReactContext()).lock()) { - if (auto xamlRoot = uiManager->tryGetXamlRoot()) { + if (auto xamlRoot = uiManager->tryGetXamlRoot(m_rootTag)) { flyoutBase6.XamlRoot(xamlRoot); m_xamlRootChangedRevoker = xamlRoot.Changed(winrt::auto_revoke, [this](auto &&, auto &&) { if (m_isLightDismissEnabled) { From c6087b5532653c219d23514862b273148f389079 Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Wed, 28 Jul 2021 13:36:45 -0400 Subject: [PATCH 5/5] Addresses review feedback --- vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp | 6 ++---- vnext/Microsoft.ReactNative/Modules/NativeUIManager.h | 5 ++--- .../Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp index acbab0df9ab..ae8c2e58834 100644 --- a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp +++ b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.cpp @@ -101,8 +101,7 @@ winrt::XamlRoot NativeUIManager::tryGetXamlRoot() { for (auto const tag : m_host->GetAllRootTags()) { if (auto shadowNode = static_cast(m_host->FindShadowNodeForTag(tag))) { if (auto uiElement10 = shadowNode->GetView().try_as()) { - if (auto xamlRoot = uiElement10.XamlRoot()) - return xamlRoot; + return uiElement10.XamlRoot(); } } } @@ -114,8 +113,7 @@ winrt::XamlRoot NativeUIManager::tryGetXamlRoot(int64_t rootTag) { if (m_host) { if (auto shadowNode = static_cast(m_host->FindShadowNodeForTag(rootTag))) { if (auto uiElement10 = shadowNode->GetView().try_as()) { - if (auto xamlRoot = uiElement10.XamlRoot()) - return xamlRoot; + return uiElement10.XamlRoot(); } } } diff --git a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.h b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.h index 4c1c4b68627..9cd9e917d80 100644 --- a/vnext/Microsoft.ReactNative/Modules/NativeUIManager.h +++ b/vnext/Microsoft.ReactNative/Modules/NativeUIManager.h @@ -89,9 +89,8 @@ class NativeUIManager final : public INativeUIManager { xaml::XamlRoot tryGetXamlRoot(); // For unparented node like Flyout, XamlRoot should be set to handle - // XamlIsland/AppWindow scenarios. Since it doesn't have parent, and all nodes - // in the tree should have the same XamlRoot, this function iterates all roots - // and try to get a valid XamlRoot. + // XamlIsland/AppWindow scenarios. This function retrieves the XamlRoot for a + // specific root tag. xaml::XamlRoot tryGetXamlRoot(int64_t rootTag); // Searches itself and its parent to get a valid XamlView. diff --git a/vnext/Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp b/vnext/Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp index a5a4eaca585..b986b79c3ce 100644 --- a/vnext/Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp +++ b/vnext/Microsoft.ReactNative/Modules/PaperUIManagerModule.cpp @@ -130,7 +130,7 @@ class UIManagerModule : public std::enable_shared_from_this, pu auto node = viewManager->createShadow(); node->m_className = std::move(viewName); node->m_tag = reactTag; - node->m_rootTag = reactTag; + node->m_rootTag = rootTag; node->m_viewManager = viewManager; node->createView(props);