diff --git a/change/react-native-windows-2020-04-11-01-26-56-unimplNotify.json b/change/react-native-windows-2020-04-11-01-26-56-unimplNotify.json
new file mode 100644
index 00000000000..52b5d38224f
--- /dev/null
+++ b/change/react-native-windows-2020-04-11-01-26-56-unimplNotify.json
@@ -0,0 +1,8 @@
+{
+ "type": "prerelease",
+ "comment": "Refactor View managers to detect unimplemented props",
+ "packageName": "react-native-windows",
+ "email": "asklar@microsoft.com",
+ "dependentChangeType": "patch",
+ "date": "2020-04-11T08:26:56.395Z"
+}
\ No newline at end of file
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
index 1fdf5719fdc..0029edaedf3 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
@@ -87,6 +87,9 @@
+
+ $(GeneratedFilesDir);$(IncludePath)
+
Use
@@ -535,7 +538,7 @@
-
+
RNW_PKG_VERSION_STR=$(RNW_PKG_VERSION_STR);
RNW_PKG_VERSION_MAJOR=$(RNW_PKG_VERSION_MAJOR);
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
index c0062f0dcdd..ebbec354228 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
@@ -741,4 +741,7 @@
{b0b76275-4a16-4939-87ee-f777cb189114}
+
+
+
\ No newline at end of file
diff --git a/vnext/Microsoft.ReactNative/RedBox.cpp b/vnext/Microsoft.ReactNative/RedBox.cpp
index 61257fdf86e..30e1f259c44 100644
--- a/vnext/Microsoft.ReactNative/RedBox.cpp
+++ b/vnext/Microsoft.ReactNative/RedBox.cpp
@@ -8,13 +8,18 @@
#include
#include
#include
+#include
#include
#include
#include
+#include
#include
#include "Unicode.h"
+namespace xaml = winrt::Windows::UI::Xaml;
+using namespace winrt::Windows::Foundation;
+
namespace Mso::React {
struct RedBox : public std::enable_shared_from_this {
@@ -47,7 +52,7 @@ struct RedBox : public std::enable_shared_from_this {
void ShowNewJSError() noexcept {
m_showing = true;
- m_popup = winrt::Windows::UI::Xaml::Controls::Primitives::Popup{};
+ m_popup = xaml::Controls::Primitives::Popup{};
const winrt::hstring xamlString =
L" {
L" "
L" "
L" "
- L" "
+ L" "
L" "
L" "
L" "
@@ -76,30 +81,27 @@ struct RedBox : public std::enable_shared_from_this {
L" "
L"";
- m_redboxContent = winrt::unbox_value(
- winrt::Windows::UI::Xaml::Markup::XamlReader::Load(xamlString));
- m_errorMessageText =
- m_redboxContent.FindName(L"ErrorMessageText").as();
- m_errorStackText = m_redboxContent.FindName(L"ErrorStackText").as();
- m_stackPanel = m_redboxContent.FindName(L"StackPanel").as();
- m_dismissButton = m_redboxContent.FindName(L"DismissButton").as();
- m_reloadButton = m_redboxContent.FindName(L"ReloadButton").as();
+ m_redboxContent = winrt::unbox_value(xaml::Markup::XamlReader::Load(xamlString));
+ m_errorMessageText = m_redboxContent.FindName(L"ErrorMessageText").as();
+ m_errorStackText = m_redboxContent.FindName(L"ErrorStackText").as();
+ m_stackPanel = m_redboxContent.FindName(L"StackPanel").as();
+ m_stackPanelUpper = m_redboxContent.FindName(L"StackPanelUpper").as();
+ m_dismissButton = m_redboxContent.FindName(L"DismissButton").as();
+ m_reloadButton = m_redboxContent.FindName(L"ReloadButton").as();
m_tokenDismiss = m_dismissButton.Click([&](
- winrt::Windows::Foundation::IInspectable const & /*sender*/,
- winrt::Windows::UI::Xaml::RoutedEventArgs const & /*args*/) noexcept { Dismiss(); });
+ IInspectable const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept { Dismiss(); });
- m_tokenReload = m_reloadButton.Click([&](
- auto const & /*sender*/, winrt::Windows::UI::Xaml::RoutedEventArgs const & /*args*/) noexcept {
+ m_tokenReload = m_reloadButton.Click([&](auto const & /*sender*/, xaml::RoutedEventArgs const & /*args*/) noexcept {
Dismiss();
Reload();
});
PopulateFrameStackUI();
- UpdateErorrMessageUI();
+ UpdateErrorMessageUI();
// Do some kind of sizing logic...
- auto window = winrt::Windows::UI::Xaml::Window::Current();
+ auto window = xaml::Window::Current();
auto windowBounds = window.Bounds();
m_redboxContent.MaxHeight(windowBounds.Height);
m_redboxContent.Height(windowBounds.Height);
@@ -111,7 +113,7 @@ struct RedBox : public std::enable_shared_from_this {
});
m_tokenClosed = m_popup.Closed([wkThis = std::weak_ptr(shared_from_this())](
- auto const & /*sender*/, winrt::Windows::Foundation::IInspectable const & /*args*/) noexcept {
+ auto const & /*sender*/, IInspectable const & /*args*/) noexcept {
if (auto pthis = wkThis.lock()) {
pthis->OnPopupClosed();
}
@@ -132,7 +134,7 @@ struct RedBox : public std::enable_shared_from_this {
m_showing = false;
m_dismissButton.Click(m_tokenDismiss);
m_reloadButton.Click(m_tokenReload);
- winrt::Windows::UI::Xaml::Window::Current().SizeChanged(m_tokenSizeChanged);
+ xaml::Window::Current().SizeChanged(m_tokenSizeChanged);
m_popup.Closed(m_tokenClosed);
m_onClosedCallback(GetId());
}
@@ -142,7 +144,20 @@ struct RedBox : public std::enable_shared_from_this {
}
private:
- void UpdateErorrMessageUI() noexcept {
+ static bool IsMetroBundlerError(const std::string &message, const std::string &type) {
+ // This string must be kept in sync with the one in formatBundlingError in
+ // node_modules\metro\src\lib\formatBundlingError.js
+ if (message.find_first_of("Metro Bundler has encountered an error") != message.npos) {
+ return true;
+ }
+ return false;
+ }
+
+#define METRO_TROUBLESHOOTING_URL "http://aka.ms/RNWTroubleshootMetro"
+#define _MAKE_WIDE_STR(x) L##x
+#define MAKE_WIDE_STR(x) _MAKE_WIDE_STR(x)
+
+ void UpdateErrorMessageUI() noexcept {
try {
auto json = folly::parseJson(m_errorInfo.Message);
if (json.count("name") && json["name"] == "Error") {
@@ -151,8 +166,83 @@ struct RedBox : public std::enable_shared_from_this {
m_errorMessageText.Text(Microsoft::Common::Unicode::Utf8ToUtf16(message));
m_errorStackText.Text(Microsoft::Common::Unicode::Utf8ToUtf16(stack));
return;
+ } else if (json.count("type") && json["type"] == "InternalError") {
+ auto message = json["message"].asString();
+ m_errorMessageText.Text(Microsoft::Common::Unicode::Utf8ToUtf16(message));
+
+ if (IsMetroBundlerError(message, json["type"].asString())) {
+ xaml::Documents::Hyperlink link;
+ link.NavigateUri(Uri(MAKE_WIDE_STR(METRO_TROUBLESHOOTING_URL)));
+ xaml::Documents::Run linkRun;
+
+ linkRun.Text(Microsoft::Common::Unicode::Utf8ToUtf16(METRO_TROUBLESHOOTING_URL));
+ link.Foreground(
+ xaml::Media::SolidColorBrush(winrt::Windows::UI::ColorHelper::FromArgb(0xff, 0xff, 0xff, 0xff)));
+ link.Inlines().Append(linkRun);
+ xaml::Documents::Run normalRun;
+ normalRun.Text(Microsoft::Common::Unicode::Utf8ToUtf16(json["type"].asString() + (" ─ See ")));
+ m_errorStackText.Inlines().Append(normalRun);
+ m_errorStackText.Inlines().Append(link);
+ } else {
+ m_errorStackText.Text(Microsoft::Common::Unicode::Utf8ToUtf16(json["type"].asString()));
+ }
+ return;
}
} catch (...) {
+ std::string doctype = "";
+ if (boost::istarts_with(m_errorInfo.Message, doctype)) {
+ auto webView = xaml::Controls::WebView(xaml::Controls::WebViewExecutionMode::SameThread);
+
+ winrt::hstring content(
+ Microsoft::Common::Unicode::Utf8ToUtf16(m_errorInfo.Message.substr(doctype.length()).c_str()));
+
+ webView.HorizontalAlignment(xaml::HorizontalAlignment::Stretch);
+ webView.VerticalAlignment(xaml::VerticalAlignment::Stretch);
+ webView.MinWidth(400);
+
+ m_stackPanel.Children().Clear();
+ m_stackPanel.Children().Append(webView);
+
+ auto dispatcher = winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
+ // XAML doesn't currently provide a way to measure a WebView control,
+ // So we're going to tell the WebView to measure itself by running some javascript,
+ // and then we'll post a task back to XAML to set the XAML WebView minimum height.
+ // The HTML we get from Metro doesn't have any styling, so we'll take advantage of
+ // the fact that we're running javascript in the WebView, to set the
+ // foreground/background to match the rest of the RedBox.
+ // setProperty returns undefined so we continue the first expression with a comma
+ // whereas the height expression gets executed because of the ||
+ // (since the setProperty calls resulted in undefined).
+ // Finally, it's important to note that JS expressions of that are not of string type
+ // need to be manually converted to string for them to get marshaled properly back here.
+ webView.NavigationCompleted(
+ [=](IInspectable const &, xaml::Controls::WebViewNavigationCompletedEventArgs const &) {
+ // #eecc0000 ARGB is #be0000 RGB (background doesn't seem to allow alpha channel in WebView)
+ std::vector args{
+ L"(document.body.style.setProperty('color', 'white'), "
+ L"document.body.style.setProperty('background', '#be0000')) "
+ L"|| document.documentElement.scrollHeight.toString()"};
+ auto async = webView.InvokeScriptAsync(L"eval", std::move(args));
+
+ async.Completed([=](IAsyncOperation const &op, auto &&state) {
+ auto result = op.GetResults();
+ int documentHeight = _wtoi(result.c_str());
+ dispatcher.TryEnqueue([=]() {
+ // Ensure the webview has a min height of the content it wants to show,
+ // and that the horizontal scrollbar that might exist, doesn't occlude the webview.
+ constexpr int horizontalScrollbarHeight = 12;
+ webView.MinHeight(documentHeight + horizontalScrollbarHeight);
+ });
+ });
+ });
+
+ webView.NavigateToString(content);
+
+ m_stackPanel.Margin(xaml::ThicknessHelper::FromUniformLength(0));
+ m_stackPanelUpper.Visibility(xaml::Visibility::Collapsed);
+
+ return;
+ }
}
// fall back to displaying the raw message string
const std::regex colorsRegex(
@@ -173,16 +263,15 @@ struct RedBox : public std::enable_shared_from_this {
L" "
L" "
L"";
- auto frameContent = winrt::unbox_value(
- winrt::Windows::UI::Xaml::Markup::XamlReader::Load(xamlFrameString));
- auto methodText = frameContent.FindName(L"MethodText").as();
- auto frameText = frameContent.FindName(L"FrameText").as();
+ auto frameContent =
+ winrt::unbox_value(xaml::Markup::XamlReader::Load(xamlFrameString));
+ auto methodText = frameContent.FindName(L"MethodText").as();
+ auto frameText = frameContent.FindName(L"FrameText").as();
methodText.Text(Microsoft::Common::Unicode::Utf8ToUtf16(frame.Method));
// When the user taps on a stack frame, tell the bundler to load that source in the users editor of choice
frameContent.Tapped([weakReactHost = m_weakReactHost, f = frame](
- winrt::Windows::Foundation::IInspectable const & /*sender*/,
- winrt::Windows::UI::Xaml::Input::TappedRoutedEventArgs const & /*e*/) {
+ IInspectable const & /*sender*/, xaml::Input::TappedRoutedEventArgs const & /*e*/) {
if (auto reactHost = weakReactHost.GetStrongPtr()) {
auto devSettings = reactHost->Options().DeveloperSettings;
std::string stackFrameUri = "http://";
@@ -191,7 +280,7 @@ struct RedBox : public std::enable_shared_from_this {
stackFrameUri.append(devSettings.SourceBundlePath.empty() ? "8081" : devSettings.SourceBundlePort);
stackFrameUri.append("/open-stack-frame");
- winrt::Windows::Foundation::Uri uri{Microsoft::Common::Unicode::Utf8ToUtf16(stackFrameUri)};
+ Uri uri{Microsoft::Common::Unicode::Utf8ToUtf16(stackFrameUri)};
winrt::Windows::Web::Http::HttpClient httpClient{};
winrt::Windows::Data::Json::JsonObject payload{};
@@ -226,13 +315,14 @@ struct RedBox : public std::enable_shared_from_this {
}
}
- winrt::Windows::UI::Xaml::Controls::StackPanel m_stackPanel{nullptr};
- winrt::Windows::UI::Xaml::Controls::Primitives::Popup m_popup{nullptr};
- winrt::Windows::UI::Xaml::Controls::Grid m_redboxContent{nullptr};
- winrt::Windows::UI::Xaml::Controls::Button m_dismissButton{nullptr};
- winrt::Windows::UI::Xaml::Controls::Button m_reloadButton{nullptr};
- winrt::Windows::UI::Xaml::Controls::TextBlock m_errorMessageText{nullptr};
- winrt::Windows::UI::Xaml::Controls::TextBlock m_errorStackText{nullptr};
+ xaml::Controls::StackPanel m_stackPanelUpper{nullptr};
+ xaml::Controls::StackPanel m_stackPanel{nullptr};
+ xaml::Controls::Primitives::Popup m_popup{nullptr};
+ xaml::Controls::Grid m_redboxContent{nullptr};
+ xaml::Controls::Button m_dismissButton{nullptr};
+ xaml::Controls::Button m_reloadButton{nullptr};
+ xaml::Controls::TextBlock m_errorMessageText{nullptr};
+ xaml::Controls::TextBlock m_errorStackText{nullptr};
bool m_showing = false;
Mso::Functor m_onClosedCallback;
diff --git a/vnext/ReactUWP/Polyester/ButtonViewManager.cpp b/vnext/ReactUWP/Polyester/ButtonViewManager.cpp
index 903485902b6..573ac85bda4 100644
--- a/vnext/ReactUWP/Polyester/ButtonViewManager.cpp
+++ b/vnext/ReactUWP/Polyester/ButtonViewManager.cpp
@@ -73,25 +73,23 @@ XamlView ButtonViewManager::CreateViewCore(int64_t /*tag*/) {
return button;
}
-void ButtonViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool ButtonViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto button = nodeToUpdate->GetView().as();
if (button == nullptr)
- return;
+ return true;
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "disabled") {
- if (propertyValue.isBool())
- button.IsEnabled(!propertyValue.asBool());
- }
-
- continue;
+ if (propertyName == "disabled") {
+ if (propertyValue.isBool())
+ button.IsEnabled(!propertyValue.asBool());
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
-
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
+
} // namespace polyester
} // namespace uwp
} // namespace react
diff --git a/vnext/ReactUWP/Polyester/ButtonViewManager.h b/vnext/ReactUWP/Polyester/ButtonViewManager.h
index ec3d2e32a13..d3a3f28c714 100644
--- a/vnext/ReactUWP/Polyester/ButtonViewManager.h
+++ b/vnext/ReactUWP/Polyester/ButtonViewManager.h
@@ -24,9 +24,12 @@ class ButtonViewManager : public ContentControlViewManager {
folly::dynamic GetExportedCustomDirectEventTypeConstants() const override;
facebook::react::ShadowNode *createShadow() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
-
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
};
diff --git a/vnext/ReactUWP/Polyester/HyperlinkViewManager.cpp b/vnext/ReactUWP/Polyester/HyperlinkViewManager.cpp
index da1abda7099..3754b765de2 100644
--- a/vnext/ReactUWP/Polyester/HyperlinkViewManager.cpp
+++ b/vnext/ReactUWP/Polyester/HyperlinkViewManager.cpp
@@ -60,31 +60,31 @@ folly::dynamic HyperlinkViewManager::GetExportedCustomDirectEventTypeConstants()
return directEvents;
}
-void HyperlinkViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool HyperlinkViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto button = nodeToUpdate->GetView().as();
if (button == nullptr)
- return;
-
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "disabled") {
- if (propertyValue.isBool())
- button.IsEnabled(!propertyValue.asBool());
- } else if (propertyName == "tooltip") {
- if (propertyValue.isString()) {
- winrt::TextBlock tooltip = winrt::TextBlock();
- tooltip.Text(asHstring(propertyValue));
- winrt::ToolTipService::SetToolTip(button, tooltip);
- }
- } else if (propertyName == "url") {
- winrt::Uri myUri(asHstring(propertyValue));
- button.NavigateUri(myUri);
+ return true;
+
+ if (propertyName == "disabled") {
+ if (propertyValue.isBool())
+ button.IsEnabled(!propertyValue.asBool());
+ } else if (propertyName == "tooltip") {
+ if (propertyValue.isString()) {
+ winrt::TextBlock tooltip = winrt::TextBlock();
+ tooltip.Text(asHstring(propertyValue));
+ winrt::ToolTipService::SetToolTip(button, tooltip);
}
+ } else if (propertyName == "url") {
+ winrt::Uri myUri(asHstring(propertyValue));
+ button.NavigateUri(myUri);
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
} // namespace polyester
diff --git a/vnext/ReactUWP/Polyester/HyperlinkViewManager.h b/vnext/ReactUWP/Polyester/HyperlinkViewManager.h
index 4e2c016151a..d276c8a746d 100644
--- a/vnext/ReactUWP/Polyester/HyperlinkViewManager.h
+++ b/vnext/ReactUWP/Polyester/HyperlinkViewManager.h
@@ -19,9 +19,12 @@ class HyperlinkViewManager : public ContentControlViewManager {
folly::dynamic GetNativeProps() const override;
folly::dynamic GetExportedCustomDirectEventTypeConstants() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
-
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
};
diff --git a/vnext/ReactUWP/Views/ActivityIndicatorViewManager.cpp b/vnext/ReactUWP/Views/ActivityIndicatorViewManager.cpp
index ef4337efc34..1e4dfcd711b 100644
--- a/vnext/ReactUWP/Views/ActivityIndicatorViewManager.cpp
+++ b/vnext/ReactUWP/Views/ActivityIndicatorViewManager.cpp
@@ -31,24 +31,23 @@ XamlView ActivityIndicatorViewManager::CreateViewCore(int64_t /*tag*/) {
return progressRing;
}
-void ActivityIndicatorViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool ActivityIndicatorViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto progressRing = nodeToUpdate->GetView().as();
if (progressRing == nullptr)
- return;
-
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "animating") {
- if (propertyValue.isBool())
- progressRing.IsActive(propertyValue.asBool());
- else if (pair.second.isNull())
- progressRing.ClearValue(winrt::ProgressRing::IsActiveProperty());
- }
+ return true;
+
+ if (propertyName == "animating") {
+ if (propertyValue.isBool())
+ progressRing.IsActive(propertyValue.asBool());
+ else if (propertyValue.isNull())
+ progressRing.ClearValue(winrt::ProgressRing::IsActiveProperty());
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyName);
}
-
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
} // namespace uwp
diff --git a/vnext/ReactUWP/Views/ActivityIndicatorViewManager.h b/vnext/ReactUWP/Views/ActivityIndicatorViewManager.h
index 73443158b6f..90e63997811 100644
--- a/vnext/ReactUWP/Views/ActivityIndicatorViewManager.h
+++ b/vnext/ReactUWP/Views/ActivityIndicatorViewManager.h
@@ -17,9 +17,12 @@ class ActivityIndicatorViewManager : public ControlViewManager {
const char *GetName() const override;
folly::dynamic GetNativeProps() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
-
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
};
diff --git a/vnext/ReactUWP/Views/CheckboxViewManager.cpp b/vnext/ReactUWP/Views/CheckboxViewManager.cpp
index 78ebd313123..7710229b8ff 100644
--- a/vnext/ReactUWP/Views/CheckboxViewManager.cpp
+++ b/vnext/ReactUWP/Views/CheckboxViewManager.cpp
@@ -85,29 +85,28 @@ XamlView CheckBoxViewManager::CreateViewCore(int64_t /*tag*/) {
return checkbox;
}
-void CheckBoxViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool CheckBoxViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto checkbox = nodeToUpdate->GetView().as();
if (checkbox == nullptr)
- return;
-
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "disabled") {
- if (propertyValue.isBool())
- checkbox.IsEnabled(!propertyValue.asBool());
- else if (pair.second.isNull())
- checkbox.ClearValue(winrt::Control::IsEnabledProperty());
- } else if (propertyName == "value") {
- if (propertyValue.isBool())
- checkbox.IsChecked(propertyValue.asBool());
- else if (pair.second.isNull())
- checkbox.ClearValue(winrt::ToggleButton::IsCheckedProperty());
- }
+ return true;
+
+ if (propertyName == "disabled") {
+ if (propertyValue.isBool())
+ checkbox.IsEnabled(!propertyValue.asBool());
+ else if (propertyValue.isNull())
+ checkbox.ClearValue(winrt::Control::IsEnabledProperty());
+ } else if (propertyName == "value") {
+ if (propertyValue.isBool())
+ checkbox.IsChecked(propertyValue.asBool());
+ else if (propertyValue.isNull())
+ checkbox.ClearValue(winrt::ToggleButton::IsCheckedProperty());
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
-
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
} // namespace uwp
diff --git a/vnext/ReactUWP/Views/CheckboxViewManager.h b/vnext/ReactUWP/Views/CheckboxViewManager.h
index 82be7007828..581aa2f8c01 100644
--- a/vnext/ReactUWP/Views/CheckboxViewManager.h
+++ b/vnext/ReactUWP/Views/CheckboxViewManager.h
@@ -19,9 +19,12 @@ class CheckBoxViewManager : public ControlViewManager {
facebook::react::ShadowNode *createShadow() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
-
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
friend class CheckBoxShadowNode;
diff --git a/vnext/ReactUWP/Views/ControlViewManager.cpp b/vnext/ReactUWP/Views/ControlViewManager.cpp
index e0bbc4fc1e4..3e359854e09 100644
--- a/vnext/ReactUWP/Views/ControlViewManager.cpp
+++ b/vnext/ReactUWP/Views/ControlViewManager.cpp
@@ -39,53 +39,48 @@ void ControlViewManager::TransferProperties(XamlView oldView, XamlView newView)
Super::TransferProperties(oldView, newView);
}
-void ControlViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool ControlViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto control(nodeToUpdate->GetView().as());
bool implementsPadding = nodeToUpdate->ImplementsPadding();
bool finalizeBorderRadius{false};
+ bool ret = true;
if (control != nullptr) {
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (TryUpdateBackgroundBrush(control, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateBorderProperties(nodeToUpdate, control, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateForeground(control, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateCornerRadiusOnNode(nodeToUpdate, control, propertyName, propertyValue)) {
- finalizeBorderRadius = true;
- continue;
- } else if (implementsPadding && TryUpdatePadding(nodeToUpdate, control, propertyName, propertyValue)) {
- continue;
- } else if (propertyName == "tabIndex") {
- if (propertyValue.isNumber()) {
- auto tabIndex = propertyValue.asDouble();
- if (tabIndex == static_cast(tabIndex)) {
- if (tabIndex < 0) {
- control.IsTabStop(false);
- control.ClearValue(winrt::Control::TabIndexProperty());
- } else {
- control.IsTabStop(true);
- control.TabIndex(static_cast(tabIndex));
- }
+ if (TryUpdateBackgroundBrush(control, propertyName, propertyValue)) {
+ } else if (TryUpdateBorderProperties(nodeToUpdate, control, propertyName, propertyValue)) {
+ } else if (TryUpdateForeground(control, propertyName, propertyValue)) {
+ } else if (TryUpdateCornerRadiusOnNode(nodeToUpdate, control, propertyName, propertyValue)) {
+ finalizeBorderRadius = true;
+ } else if (implementsPadding && TryUpdatePadding(nodeToUpdate, control, propertyName, propertyValue)) {
+ } else if (propertyName == "tabIndex") {
+ if (propertyValue.isNumber()) {
+ auto tabIndex = propertyValue.asDouble();
+ if (tabIndex == static_cast(tabIndex)) {
+ if (tabIndex < 0) {
+ control.IsTabStop(false);
+ control.ClearValue(winrt::Control::TabIndexProperty());
+ } else {
+ control.IsTabStop(true);
+ control.TabIndex(static_cast(tabIndex));
}
- } else if (propertyValue.isNull()) {
- control.ClearValue(winrt::Control::TabIndexProperty());
}
+ } else if (propertyValue.isNull()) {
+ control.ClearValue(winrt::Control::TabIndexProperty());
}
+ } else {
+ ret = Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
}
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
-
if (finalizeBorderRadius && control.try_as()) {
// Control.CornerRadius is only supported on >= RS5, setting borderRadius on Controls have no effect < RS5
UpdateCornerRadiusOnElement(nodeToUpdate, control);
}
+ return ret;
}
void ControlViewManager::OnViewCreated(XamlView view) {
diff --git a/vnext/ReactUWP/Views/FrameworkElementViewManager.cpp b/vnext/ReactUWP/Views/FrameworkElementViewManager.cpp
index 6146329cc0c..f1c223c7632 100644
--- a/vnext/ReactUWP/Views/FrameworkElementViewManager.cpp
+++ b/vnext/ReactUWP/Views/FrameworkElementViewManager.cpp
@@ -150,326 +150,313 @@ folly::dynamic FrameworkElementViewManager::GetNativeProps() const {
return props;
}
-void FrameworkElementViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool FrameworkElementViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto element(nodeToUpdate->GetView().as());
if (element != nullptr) {
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "opacity") {
- if (propertyValue.isNumber()) {
- double opacity = propertyValue.asDouble();
- if (opacity >= 0 && opacity <= 1)
- element.Opacity(opacity);
- // else
- // TODO report error
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::UIElement::OpacityProperty());
- continue;
- }
- } else if (propertyName == "transform") {
- if (element.try_as()) // Works on 19H1+
- {
- if (propertyValue.isArray()) {
- assert(propertyValue.size() == 16);
- winrt::Windows::Foundation::Numerics::float4x4 transformMatrix;
- transformMatrix.m11 = static_cast(propertyValue[0].asDouble());
- transformMatrix.m12 = static_cast(propertyValue[1].asDouble());
- transformMatrix.m13 = static_cast(propertyValue[2].asDouble());
- transformMatrix.m14 = static_cast(propertyValue[3].asDouble());
- transformMatrix.m21 = static_cast(propertyValue[4].asDouble());
- transformMatrix.m22 = static_cast(propertyValue[5].asDouble());
- transformMatrix.m23 = static_cast(propertyValue[6].asDouble());
- transformMatrix.m24 = static_cast(propertyValue[7].asDouble());
- transformMatrix.m31 = static_cast(propertyValue[8].asDouble());
- transformMatrix.m32 = static_cast(propertyValue[9].asDouble());
- transformMatrix.m33 = static_cast(propertyValue[10].asDouble());
- transformMatrix.m34 = static_cast(propertyValue[11].asDouble());
- transformMatrix.m41 = static_cast(propertyValue[12].asDouble());
- transformMatrix.m42 = static_cast(propertyValue[13].asDouble());
- transformMatrix.m43 = static_cast(propertyValue[14].asDouble());
- transformMatrix.m44 = static_cast(propertyValue[15].asDouble());
-
- ApplyTransformMatrix(element, nodeToUpdate, transformMatrix);
- } else if (propertyValue.isNull()) {
- element.TransformMatrix(winrt::Windows::Foundation::Numerics::float4x4::identity());
- }
- }
- } else if (propertyName == "width") {
- if (propertyValue.isNumber()) {
- double width = propertyValue.asDouble();
- if (width >= 0)
- element.Width(width);
- // else
- // TODO report error
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::FrameworkElement::WidthProperty());
- continue;
- }
-
- } else if (propertyName == "height") {
- if (propertyValue.isNumber()) {
- double height = propertyValue.asDouble();
- if (height >= 0)
- element.Height(height);
- // else
- // TODO report error
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::FrameworkElement::HeightProperty());
- continue;
- }
- } else if (propertyName == "minWidth") {
- if (propertyValue.isNumber()) {
- double minWidth = propertyValue.asDouble();
- if (minWidth >= 0)
- element.MinWidth(minWidth);
- // else
- // TODO report error
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::FrameworkElement::MinWidthProperty());
- continue;
- }
- } else if (propertyName == "maxWidth") {
- if (propertyValue.isNumber()) {
- double maxWidth = propertyValue.asDouble();
- if (maxWidth >= 0)
- element.MaxWidth(maxWidth);
- // else
- // TODO report error
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::FrameworkElement::MaxWidthProperty());
- continue;
- }
-
- } else if (propertyName == "minHeight") {
- if (propertyValue.isNumber()) {
- double minHeight = propertyValue.asDouble();
- if (minHeight >= 0)
- element.MinHeight(minHeight);
- // else
- // TODO report error
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::FrameworkElement::MinHeightProperty());
- continue;
- }
- } else if (propertyName == "maxHeight") {
- if (propertyValue.isNumber()) {
- double maxHeight = propertyValue.asDouble();
- if (maxHeight >= 0)
- element.MaxHeight(maxHeight);
- // else
- // TODO report error
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::FrameworkElement::MaxHeightProperty());
- continue;
- }
-
- } else if (propertyName == "accessibilityHint") {
- if (propertyValue.isString()) {
- auto value = react::uwp::asHstring(propertyValue);
- auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value);
-
- element.SetValue(winrt::AutomationProperties::HelpTextProperty(), boxedValue);
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::AutomationProperties::HelpTextProperty());
- }
- } else if (propertyName == "accessibilityLabel") {
- if (propertyValue.isString()) {
- auto value = react::uwp::asHstring(propertyValue);
- auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value);
-
- element.SetValue(winrt::AutomationProperties::NameProperty(), boxedValue);
+ if (propertyName == "opacity") {
+ if (propertyValue.isNumber()) {
+ double opacity = propertyValue.asDouble();
+ if (opacity >= 0 && opacity <= 1)
+ element.Opacity(opacity);
+ // else
+ // TODO report error
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::UIElement::OpacityProperty());
+ }
+ } else if (propertyName == "transform") {
+ if (element.try_as()) // Works on 19H1+
+ {
+ if (propertyValue.isArray()) {
+ assert(propertyValue.size() == 16);
+ winrt::Windows::Foundation::Numerics::float4x4 transformMatrix;
+ transformMatrix.m11 = static_cast(propertyValue[0].asDouble());
+ transformMatrix.m12 = static_cast(propertyValue[1].asDouble());
+ transformMatrix.m13 = static_cast(propertyValue[2].asDouble());
+ transformMatrix.m14 = static_cast(propertyValue[3].asDouble());
+ transformMatrix.m21 = static_cast(propertyValue[4].asDouble());
+ transformMatrix.m22 = static_cast(propertyValue[5].asDouble());
+ transformMatrix.m23 = static_cast(propertyValue[6].asDouble());
+ transformMatrix.m24 = static_cast(propertyValue[7].asDouble());
+ transformMatrix.m31 = static_cast(propertyValue[8].asDouble());
+ transformMatrix.m32 = static_cast(propertyValue[9].asDouble());
+ transformMatrix.m33 = static_cast(propertyValue[10].asDouble());
+ transformMatrix.m34 = static_cast(propertyValue[11].asDouble());
+ transformMatrix.m41 = static_cast(propertyValue[12].asDouble());
+ transformMatrix.m42 = static_cast(propertyValue[13].asDouble());
+ transformMatrix.m43 = static_cast(propertyValue[14].asDouble());
+ transformMatrix.m44 = static_cast(propertyValue[15].asDouble());
+
+ ApplyTransformMatrix(element, nodeToUpdate, transformMatrix);
} else if (propertyValue.isNull()) {
- element.ClearValue(winrt::AutomationProperties::NameProperty());
- }
- AnnounceLiveRegionChangedIfNeeded(element);
- } else if (propertyName == "accessible") {
- if (propertyValue.isBool()) {
- if (!propertyValue.asBool())
- winrt::AutomationProperties::SetAccessibilityView(element, winrt::Peers::AccessibilityView::Raw);
+ element.TransformMatrix(winrt::Windows::Foundation::Numerics::float4x4::identity());
}
- } else if (propertyName == "accessibilityLiveRegion") {
- if (propertyValue.isString()) {
- auto value = propertyValue.getString();
+ }
+ } else if (propertyName == "width") {
+ if (propertyValue.isNumber()) {
+ double width = propertyValue.asDouble();
+ if (width >= 0)
+ element.Width(width);
+ // else
+ // TODO report error
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::FrameworkElement::WidthProperty());
+ }
- auto liveSetting = winrt::AutomationLiveSetting::Off;
+ } else if (propertyName == "height") {
+ if (propertyValue.isNumber()) {
+ double height = propertyValue.asDouble();
+ if (height >= 0)
+ element.Height(height);
+ // else
+ // TODO report error
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::FrameworkElement::HeightProperty());
+ }
+ } else if (propertyName == "minWidth") {
+ if (propertyValue.isNumber()) {
+ double minWidth = propertyValue.asDouble();
+ if (minWidth >= 0)
+ element.MinWidth(minWidth);
+ // else
+ // TODO report error
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::FrameworkElement::MinWidthProperty());
+ }
+ } else if (propertyName == "maxWidth") {
+ if (propertyValue.isNumber()) {
+ double maxWidth = propertyValue.asDouble();
+ if (maxWidth >= 0)
+ element.MaxWidth(maxWidth);
+ // else
+ // TODO report error
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::FrameworkElement::MaxWidthProperty());
+ }
- if (value == "polite") {
- liveSetting = winrt::AutomationLiveSetting::Polite;
- } else if (value == "assertive") {
- liveSetting = winrt::AutomationLiveSetting::Assertive;
- }
+ } else if (propertyName == "minHeight") {
+ if (propertyValue.isNumber()) {
+ double minHeight = propertyValue.asDouble();
+ if (minHeight >= 0)
+ element.MinHeight(minHeight);
+ // else
+ // TODO report error
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::FrameworkElement::MinHeightProperty());
+ }
+ } else if (propertyName == "maxHeight") {
+ if (propertyValue.isNumber()) {
+ double maxHeight = propertyValue.asDouble();
+ if (maxHeight >= 0)
+ element.MaxHeight(maxHeight);
+ // else
+ // TODO report error
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::FrameworkElement::MaxHeightProperty());
+ }
- element.SetValue(winrt::AutomationProperties::LiveSettingProperty(), winrt::box_value(liveSetting));
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::AutomationProperties::LiveSettingProperty());
- }
- AnnounceLiveRegionChangedIfNeeded(element);
- } else if (propertyName == "accessibilityPosInSet") {
- if (propertyValue.isNumber()) {
- auto value = static_cast(propertyValue.asDouble());
- auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateInt32(value);
+ } else if (propertyName == "accessibilityHint") {
+ if (propertyValue.isString()) {
+ auto value = react::uwp::asHstring(propertyValue);
+ auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value);
- element.SetValue(winrt::AutomationProperties::PositionInSetProperty(), boxedValue);
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::AutomationProperties::PositionInSetProperty());
- }
- } else if (propertyName == "accessibilitySetSize") {
- if (propertyValue.isNumber()) {
- auto value = static_cast(propertyValue.asDouble());
- auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateInt32(value);
+ element.SetValue(winrt::AutomationProperties::HelpTextProperty(), boxedValue);
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::AutomationProperties::HelpTextProperty());
+ }
+ } else if (propertyName == "accessibilityLabel") {
+ if (propertyValue.isString()) {
+ auto value = react::uwp::asHstring(propertyValue);
+ auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value);
+
+ element.SetValue(winrt::AutomationProperties::NameProperty(), boxedValue);
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::AutomationProperties::NameProperty());
+ }
+ AnnounceLiveRegionChangedIfNeeded(element);
+ } else if (propertyName == "accessible") {
+ if (propertyValue.isBool()) {
+ if (!propertyValue.asBool())
+ winrt::AutomationProperties::SetAccessibilityView(element, winrt::Peers::AccessibilityView::Raw);
+ }
+ } else if (propertyName == "accessibilityLiveRegion") {
+ if (propertyValue.isString()) {
+ auto value = propertyValue.getString();
- element.SetValue(winrt::AutomationProperties::SizeOfSetProperty(), boxedValue);
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::AutomationProperties::SizeOfSetProperty());
- }
- } else if (propertyName == "accessibilityRole") {
- if (propertyValue.isString()) {
- const std::string &role = propertyValue.getString();
- if (role == "none")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::None);
- else if (role == "button")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Button);
- else if (role == "link")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Link);
- else if (role == "search")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Search);
- else if (role == "image")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Image);
- else if (role == "keyboardkey")
- DynamicAutomationProperties::SetAccessibilityRole(
- element, winrt::react::uwp::AccessibilityRoles::KeyboardKey);
- else if (role == "text")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Text);
- else if (role == "adjustable")
- DynamicAutomationProperties::SetAccessibilityRole(
- element, winrt::react::uwp::AccessibilityRoles::Adjustable);
- else if (role == "imagebutton")
- DynamicAutomationProperties::SetAccessibilityRole(
- element, winrt::react::uwp::AccessibilityRoles::ImageButton);
- else if (role == "header")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Header);
- else if (role == "summary")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Summary);
- else if (role == "alert")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Alert);
- else if (role == "checkbox")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::CheckBox);
- else if (role == "combobox")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::ComboBox);
- else if (role == "menu")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Menu);
- else if (role == "menubar")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::MenuBar);
- else if (role == "menuitem")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::MenuItem);
- else if (role == "progressbar")
- DynamicAutomationProperties::SetAccessibilityRole(
- element, winrt::react::uwp::AccessibilityRoles::ProgressBar);
- else if (role == "radio")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Radio);
- else if (role == "radiogroup")
- DynamicAutomationProperties::SetAccessibilityRole(
- element, winrt::react::uwp::AccessibilityRoles::RadioGroup);
- else if (role == "scrollbar")
- DynamicAutomationProperties::SetAccessibilityRole(
- element, winrt::react::uwp::AccessibilityRoles::ScrollBar);
- else if (role == "spinbutton")
- DynamicAutomationProperties::SetAccessibilityRole(
- element, winrt::react::uwp::AccessibilityRoles::SpinButton);
- else if (role == "switch")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Switch);
- else if (role == "tab")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Tab);
- else if (role == "tablist")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::TabList);
- else if (role == "timer")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Timer);
- else if (role == "toolbar")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::ToolBar);
- else if (role == "list")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::List);
- else if (role == "listitem")
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::ListItem);
- else
- DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Unknown);
- } else if (propertyValue.isNull()) {
- element.ClearValue(DynamicAutomationProperties::AccessibilityRoleProperty());
- }
- } else if (propertyName == "accessibilityStates") {
- bool states[static_cast(winrt::react::uwp::AccessibilityStates::CountStates)] = {};
+ auto liveSetting = winrt::AutomationLiveSetting::Off;
- if (propertyValue.isArray()) {
- for (const auto &state : propertyValue) {
- if (!state.isString())
- continue;
-
- if (state.getString() == "selected")
- states[static_cast(winrt::react::uwp::AccessibilityStates::Selected)] = true;
- else if (state.getString() == "disabled")
- states[static_cast(winrt::react::uwp::AccessibilityStates::Disabled)] = true;
- else if (state.getString() == "checked")
- states[static_cast(winrt::react::uwp::AccessibilityStates::Checked)] = true;
- else if (state.getString() == "unchecked")
- states[static_cast(winrt::react::uwp::AccessibilityStates::Unchecked)] = true;
- else if (state.getString() == "busy")
- states[static_cast(winrt::react::uwp::AccessibilityStates::Busy)] = true;
- else if (state.getString() == "expanded")
- states[static_cast(winrt::react::uwp::AccessibilityStates::Expanded)] = true;
- else if (state.getString() == "collapsed")
- states[static_cast(winrt::react::uwp::AccessibilityStates::Collapsed)] = true;
- }
+ if (value == "polite") {
+ liveSetting = winrt::AutomationLiveSetting::Polite;
+ } else if (value == "assertive") {
+ liveSetting = winrt::AutomationLiveSetting::Assertive;
}
- DynamicAutomationProperties::SetAccessibilityStateSelected(
- element, states[static_cast(winrt::react::uwp::AccessibilityStates::Selected)]);
- DynamicAutomationProperties::SetAccessibilityStateDisabled(
- element, states[static_cast(winrt::react::uwp::AccessibilityStates::Disabled)]);
- DynamicAutomationProperties::SetAccessibilityStateChecked(
- element, states[static_cast(winrt::react::uwp::AccessibilityStates::Checked)]);
- DynamicAutomationProperties::SetAccessibilityStateUnchecked(
- element, states[static_cast(winrt::react::uwp::AccessibilityStates::Unchecked)]);
- DynamicAutomationProperties::SetAccessibilityStateBusy(
- element, states[static_cast(winrt::react::uwp::AccessibilityStates::Busy)]);
- DynamicAutomationProperties::SetAccessibilityStateExpanded(
- element, states[static_cast(winrt::react::uwp::AccessibilityStates::Expanded)]);
- DynamicAutomationProperties::SetAccessibilityStateCollapsed(
- element, states[static_cast(winrt::react::uwp::AccessibilityStates::Collapsed)]);
- } else if (propertyName == "testID") {
- if (propertyValue.isString()) {
- auto value = react::uwp::asHstring(propertyValue);
- auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value);
-
- element.SetValue(winrt::AutomationProperties::AutomationIdProperty(), boxedValue);
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::AutomationProperties::AutomationIdProperty());
- }
- } else if (propertyName == "tooltip") {
- if (propertyValue.isString()) {
- winrt::TextBlock tooltip = winrt::TextBlock();
- tooltip.Text(asHstring(propertyValue));
- winrt::ToolTipService::SetToolTip(element, tooltip);
+ element.SetValue(winrt::AutomationProperties::LiveSettingProperty(), winrt::box_value(liveSetting));
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::AutomationProperties::LiveSettingProperty());
+ }
+ AnnounceLiveRegionChangedIfNeeded(element);
+ } else if (propertyName == "accessibilityPosInSet") {
+ if (propertyValue.isNumber()) {
+ auto value = static_cast(propertyValue.asDouble());
+ auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateInt32(value);
+
+ element.SetValue(winrt::AutomationProperties::PositionInSetProperty(), boxedValue);
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::AutomationProperties::PositionInSetProperty());
+ }
+ } else if (propertyName == "accessibilitySetSize") {
+ if (propertyValue.isNumber()) {
+ auto value = static_cast(propertyValue.asDouble());
+ auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateInt32(value);
+
+ element.SetValue(winrt::AutomationProperties::SizeOfSetProperty(), boxedValue);
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::AutomationProperties::SizeOfSetProperty());
+ }
+ } else if (propertyName == "accessibilityRole") {
+ if (propertyValue.isString()) {
+ const std::string &role = propertyValue.getString();
+ if (role == "none")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::None);
+ else if (role == "button")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Button);
+ else if (role == "link")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Link);
+ else if (role == "search")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Search);
+ else if (role == "image")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Image);
+ else if (role == "keyboardkey")
+ DynamicAutomationProperties::SetAccessibilityRole(
+ element, winrt::react::uwp::AccessibilityRoles::KeyboardKey);
+ else if (role == "text")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Text);
+ else if (role == "adjustable")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Adjustable);
+ else if (role == "imagebutton")
+ DynamicAutomationProperties::SetAccessibilityRole(
+ element, winrt::react::uwp::AccessibilityRoles::ImageButton);
+ else if (role == "header")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Header);
+ else if (role == "summary")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Summary);
+ else if (role == "alert")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Alert);
+ else if (role == "checkbox")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::CheckBox);
+ else if (role == "combobox")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::ComboBox);
+ else if (role == "menu")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Menu);
+ else if (role == "menubar")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::MenuBar);
+ else if (role == "menuitem")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::MenuItem);
+ else if (role == "progressbar")
+ DynamicAutomationProperties::SetAccessibilityRole(
+ element, winrt::react::uwp::AccessibilityRoles::ProgressBar);
+ else if (role == "radio")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Radio);
+ else if (role == "radiogroup")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::RadioGroup);
+ else if (role == "scrollbar")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::ScrollBar);
+ else if (role == "spinbutton")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::SpinButton);
+ else if (role == "switch")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Switch);
+ else if (role == "tab")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Tab);
+ else if (role == "tablist")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::TabList);
+ else if (role == "timer")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Timer);
+ else if (role == "toolbar")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::ToolBar);
+ else if (role == "list")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::List);
+ else if (role == "listitem")
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::ListItem);
+ else
+ DynamicAutomationProperties::SetAccessibilityRole(element, winrt::react::uwp::AccessibilityRoles::Unknown);
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(DynamicAutomationProperties::AccessibilityRoleProperty());
+ }
+ } else if (propertyName == "accessibilityStates") {
+ bool states[static_cast(winrt::react::uwp::AccessibilityStates::CountStates)] = {};
+
+ if (propertyValue.isArray()) {
+ for (const auto &state : propertyValue) {
+ if (!state.isString())
+ continue;
+
+ if (state.getString() == "selected")
+ states[static_cast(winrt::react::uwp::AccessibilityStates::Selected)] = true;
+ else if (state.getString() == "disabled")
+ states[static_cast(winrt::react::uwp::AccessibilityStates::Disabled)] = true;
+ else if (state.getString() == "checked")
+ states[static_cast(winrt::react::uwp::AccessibilityStates::Checked)] = true;
+ else if (state.getString() == "unchecked")
+ states[static_cast(winrt::react::uwp::AccessibilityStates::Unchecked)] = true;
+ else if (state.getString() == "busy")
+ states[static_cast(winrt::react::uwp::AccessibilityStates::Busy)] = true;
+ else if (state.getString() == "expanded")
+ states[static_cast(winrt::react::uwp::AccessibilityStates::Expanded)] = true;
+ else if (state.getString() == "collapsed")
+ states[static_cast(winrt::react::uwp::AccessibilityStates::Collapsed)] = true;
}
- } else if (propertyName == "zIndex") {
- if (propertyValue.isNumber()) {
- auto value = static_cast(propertyValue.asDouble());
- auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateInt32(value);
+ }
- element.SetValue(winrt::Canvas::ZIndexProperty(), boxedValue);
- } else if (propertyValue.isNull()) {
- element.ClearValue(winrt::Canvas::ZIndexProperty());
- }
- } else if (TryUpdateFlowDirection(element, propertyName, propertyValue)) {
- continue;
- } else if (propertyName == "accessibilityActions") {
- auto value = json_type_traits>::parseJson(propertyValue);
- DynamicAutomationProperties::SetAccessibilityActions(element, value);
+ DynamicAutomationProperties::SetAccessibilityStateSelected(
+ element, states[static_cast(winrt::react::uwp::AccessibilityStates::Selected)]);
+ DynamicAutomationProperties::SetAccessibilityStateDisabled(
+ element, states[static_cast(winrt::react::uwp::AccessibilityStates::Disabled)]);
+ DynamicAutomationProperties::SetAccessibilityStateChecked(
+ element, states[static_cast(winrt::react::uwp::AccessibilityStates::Checked)]);
+ DynamicAutomationProperties::SetAccessibilityStateUnchecked(
+ element, states[static_cast(winrt::react::uwp::AccessibilityStates::Unchecked)]);
+ DynamicAutomationProperties::SetAccessibilityStateBusy(
+ element, states[static_cast(winrt::react::uwp::AccessibilityStates::Busy)]);
+ DynamicAutomationProperties::SetAccessibilityStateExpanded(
+ element, states[static_cast(winrt::react::uwp::AccessibilityStates::Expanded)]);
+ DynamicAutomationProperties::SetAccessibilityStateCollapsed(
+ element, states[static_cast(winrt::react::uwp::AccessibilityStates::Collapsed)]);
+ } else if (propertyName == "testID") {
+ if (propertyValue.isString()) {
+ auto value = react::uwp::asHstring(propertyValue);
+ auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateString(value);
+
+ element.SetValue(winrt::AutomationProperties::AutomationIdProperty(), boxedValue);
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::AutomationProperties::AutomationIdProperty());
}
+ } else if (propertyName == "tooltip") {
+ if (propertyValue.isString()) {
+ winrt::TextBlock tooltip = winrt::TextBlock();
+ tooltip.Text(asHstring(propertyValue));
+ winrt::ToolTipService::SetToolTip(element, tooltip);
+ }
+ } else if (propertyName == "zIndex") {
+ if (propertyValue.isNumber()) {
+ auto value = static_cast(propertyValue.asDouble());
+ auto boxedValue = winrt::Windows::Foundation::PropertyValue::CreateInt32(value);
+
+ element.SetValue(winrt::Canvas::ZIndexProperty(), boxedValue);
+ } else if (propertyValue.isNull()) {
+ element.ClearValue(winrt::Canvas::ZIndexProperty());
+ }
+ } else if (TryUpdateFlowDirection(element, propertyName, propertyValue)) {
+ } else if (propertyName == "accessibilityActions") {
+ auto value = json_type_traits>::parseJson(propertyValue);
+ DynamicAutomationProperties::SetAccessibilityActions(element, value);
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
}
-
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
// Applies a TransformMatrix to the backing UIElement.
diff --git a/vnext/ReactUWP/Views/Image/ImageViewManager.cpp b/vnext/ReactUWP/Views/Image/ImageViewManager.cpp
index c5465508007..a0571d5b94b 100644
--- a/vnext/ReactUWP/Views/Image/ImageViewManager.cpp
+++ b/vnext/ReactUWP/Views/Image/ImageViewManager.cpp
@@ -111,36 +111,36 @@ facebook::react::ShadowNode *ImageViewManager::createShadow() const {
return new ImageShadowNode();
}
-void ImageViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool ImageViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto grid{nodeToUpdate->GetView().as()};
if (grid == nullptr)
- return;
+ return true;
bool finalizeBorderRadius{false};
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName{pair.first.getString()};
- const folly::dynamic &propertyValue{pair.second};
-
- if (propertyName == "source") {
- setSource(grid, propertyValue);
- } else if (propertyName == "resizeMode") {
- auto resizeMode{json_type_traits::parseJson(propertyValue)};
- auto reactImage{grid.as()};
- reactImage->ResizeMode(resizeMode);
- } else if (TryUpdateCornerRadiusOnNode(nodeToUpdate, grid, propertyName, propertyValue)) {
- finalizeBorderRadius = true;
- continue;
- } else if (TryUpdateBorderProperties(nodeToUpdate, grid, propertyName, propertyValue)) {
- continue;
- }
+ bool ret = true;
+
+ if (propertyName == "source") {
+ setSource(grid, propertyValue);
+ } else if (propertyName == "resizeMode") {
+ auto resizeMode{json_type_traits::parseJson(propertyValue)};
+ auto reactImage{grid.as()};
+ reactImage->ResizeMode(resizeMode);
+ } else if (TryUpdateCornerRadiusOnNode(nodeToUpdate, grid, propertyName, propertyValue)) {
+ finalizeBorderRadius = true;
+ } else if (TryUpdateBorderProperties(nodeToUpdate, grid, propertyName, propertyValue)) {
+ } else {
+ ret = Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
// TODO: overflow
}
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
-
if (finalizeBorderRadius)
UpdateCornerRadiusOnElement(nodeToUpdate, grid);
+
+ return ret;
}
void ImageViewManager::EmitImageEvent(winrt::Grid grid, const char *eventName, ReactImageSource &source) {
diff --git a/vnext/ReactUWP/Views/Image/ImageViewManager.h b/vnext/ReactUWP/Views/Image/ImageViewManager.h
index a27d18c7eab..88f49a1adf4 100644
--- a/vnext/ReactUWP/Views/Image/ImageViewManager.h
+++ b/vnext/ReactUWP/Views/Image/ImageViewManager.h
@@ -14,7 +14,6 @@ class ImageViewManager : public FrameworkElementViewManager {
ImageViewManager(const std::shared_ptr &reactInstance);
const char *GetName() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
folly::dynamic GetExportedCustomDirectEventTypeConstants() const override;
folly::dynamic GetNativeProps() const override;
@@ -22,6 +21,11 @@ class ImageViewManager : public FrameworkElementViewManager {
void EmitImageEvent(winrt::Windows::UI::Xaml::Controls::Grid grid, const char *eventName, ReactImageSource &source);
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
private:
diff --git a/vnext/ReactUWP/Views/RawTextViewManager.cpp b/vnext/ReactUWP/Views/RawTextViewManager.cpp
index 0b43ed7d075..c8141de02ac 100644
--- a/vnext/ReactUWP/Views/RawTextViewManager.cpp
+++ b/vnext/ReactUWP/Views/RawTextViewManager.cpp
@@ -38,35 +38,36 @@ XamlView RawTextViewManager::CreateViewCore(int64_t /*tag*/) {
return run;
}
-void RawTextViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool RawTextViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto run = nodeToUpdate->GetView().as();
if (run == nullptr)
- return;
-
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "text") {
- run.Text(asHstring(propertyValue));
- if (nodeToUpdate->GetParent() != -1) {
- if (auto instance = this->m_wkReactInstance.lock()) {
- const ShadowNodeBase *parent = static_cast(
- instance->NativeUIManager()->getHost()->FindShadowNodeForTag(nodeToUpdate->GetParent()));
- if (parent && parent->m_children.size() == 1) {
- auto view = parent->GetView();
- auto textBlock = view.try_as();
- if (textBlock != nullptr) {
- textBlock.Text(run.Text());
- }
+ return true;
+
+ if (propertyName == "text") {
+ run.Text(asHstring(propertyValue));
+
+ if (nodeToUpdate->GetParent() != -1) {
+ if (auto instance = this->m_wkReactInstance.lock()) {
+ const ShadowNodeBase *parent = static_cast(
+ instance->NativeUIManager()->getHost()->FindShadowNodeForTag(nodeToUpdate->GetParent()));
+ if (parent && parent->m_children.size() == 1) {
+ auto view = parent->GetView();
+ auto textBlock = view.try_as();
+ if (textBlock != nullptr) {
+ textBlock.Text(run.Text());
}
-
- NotifyAncestorsTextChanged(instance.operator->(), nodeToUpdate);
}
+
+ NotifyAncestorsTextChanged(instance.operator->(), nodeToUpdate);
}
}
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
void RawTextViewManager::NotifyAncestorsTextChanged(IReactInstance *instance, ShadowNodeBase *nodeToUpdate) {
diff --git a/vnext/ReactUWP/Views/RawTextViewManager.h b/vnext/ReactUWP/Views/RawTextViewManager.h
index 78315528cbf..6974cd6b909 100644
--- a/vnext/ReactUWP/Views/RawTextViewManager.h
+++ b/vnext/ReactUWP/Views/RawTextViewManager.h
@@ -17,7 +17,6 @@ class RawTextViewManager : public ViewManagerBase {
RawTextViewManager(const std::shared_ptr &reactInstance);
const char *GetName() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
void SetLayoutProps(
ShadowNodeBase &nodeToUpdate,
@@ -29,6 +28,11 @@ class RawTextViewManager : public ViewManagerBase {
bool RequiresYogaNode() const override;
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
private:
diff --git a/vnext/ReactUWP/Views/SliderViewManager.cpp b/vnext/ReactUWP/Views/SliderViewManager.cpp
index b4c3648a171..4dbb979aaa2 100644
--- a/vnext/ReactUWP/Views/SliderViewManager.cpp
+++ b/vnext/ReactUWP/Views/SliderViewManager.cpp
@@ -61,29 +61,28 @@ XamlView SliderViewManager::CreateViewCore(int64_t /*tag*/) {
return slider;
}
-void SliderViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool SliderViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto slider = nodeToUpdate->GetView().as();
if (slider == nullptr)
- return;
-
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "disabled") {
- if (propertyValue.isBool())
- slider.IsEnabled(!propertyValue.asBool());
- else if (pair.second.isNull())
- slider.ClearValue(winrt::Control::IsEnabledProperty());
- } else if (propertyName == "value") {
- if (propertyValue.isNumber())
- slider.Value(propertyValue.asDouble());
- else if (pair.second.isNull())
- slider.Value(0);
- }
+ return true;
+
+ if (propertyName == "disabled") {
+ if (propertyValue.isBool())
+ slider.IsEnabled(!propertyValue.asBool());
+ else if (propertyValue.isNull())
+ slider.ClearValue(winrt::Control::IsEnabledProperty());
+ } else if (propertyName == "value") {
+ if (propertyValue.isNumber())
+ slider.Value(propertyValue.asDouble());
+ else if (propertyValue.isNull())
+ slider.Value(0);
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
-
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
} // namespace uwp
diff --git a/vnext/ReactUWP/Views/SliderViewManager.h b/vnext/ReactUWP/Views/SliderViewManager.h
index c7a1e4b80c4..8d28783cbb7 100644
--- a/vnext/ReactUWP/Views/SliderViewManager.h
+++ b/vnext/ReactUWP/Views/SliderViewManager.h
@@ -19,9 +19,12 @@ class SliderViewManager : public ControlViewManager {
facebook::react::ShadowNode *createShadow() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
-
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
friend class SliderShadowNode;
diff --git a/vnext/ReactUWP/Views/SwitchViewManager.cpp b/vnext/ReactUWP/Views/SwitchViewManager.cpp
index af5e8fa9c5f..e5ad8a0c5a5 100644
--- a/vnext/ReactUWP/Views/SwitchViewManager.cpp
+++ b/vnext/ReactUWP/Views/SwitchViewManager.cpp
@@ -136,28 +136,28 @@ XamlView SwitchViewManager::CreateViewCore(int64_t /*tag*/) {
return toggleSwitch;
}
-void SwitchViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool SwitchViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto toggleSwitch = nodeToUpdate->GetView().as();
if (toggleSwitch == nullptr)
- return;
-
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "disabled") {
- if (propertyValue.isBool())
- toggleSwitch.IsEnabled(!propertyValue.asBool());
- else if (pair.second.isNull())
- toggleSwitch.ClearValue(winrt::Control::IsEnabledProperty());
- } else if (propertyName == "value") {
- if (propertyValue.isBool())
- toggleSwitch.IsOn(propertyValue.asBool());
- else if (pair.second.isNull())
- toggleSwitch.ClearValue(winrt::ToggleSwitch::IsOnProperty());
- }
+ return true;
+
+ if (propertyName == "disabled") {
+ if (propertyValue.isBool())
+ toggleSwitch.IsEnabled(!propertyValue.asBool());
+ else if (propertyValue.isNull())
+ toggleSwitch.ClearValue(winrt::Control::IsEnabledProperty());
+ } else if (propertyName == "value") {
+ if (propertyValue.isBool())
+ toggleSwitch.IsOn(propertyValue.asBool());
+ else if (propertyValue.isNull())
+ toggleSwitch.ClearValue(winrt::ToggleSwitch::IsOnProperty());
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
} // namespace uwp
diff --git a/vnext/ReactUWP/Views/SwitchViewManager.h b/vnext/ReactUWP/Views/SwitchViewManager.h
index d45a273ba12..aaa6089c809 100644
--- a/vnext/ReactUWP/Views/SwitchViewManager.h
+++ b/vnext/ReactUWP/Views/SwitchViewManager.h
@@ -17,9 +17,13 @@ class SwitchViewManager : public ControlViewManager {
const char *GetName() const override;
folly::dynamic GetNativeProps() const override;
facebook::react::ShadowNode *createShadow() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
friend class SwitchShadowNode;
diff --git a/vnext/ReactUWP/Views/TextViewManager.cpp b/vnext/ReactUWP/Views/TextViewManager.cpp
index 303f06c8c60..eeee6140d2c 100644
--- a/vnext/ReactUWP/Views/TextViewManager.cpp
+++ b/vnext/ReactUWP/Views/TextViewManager.cpp
@@ -85,68 +85,61 @@ XamlView TextViewManager::CreateViewCore(int64_t /*tag*/) {
return textBlock;
}
-void TextViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool TextViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto textBlock = nodeToUpdate->GetView().as();
if (textBlock == nullptr)
- return;
-
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (TryUpdateForeground(textBlock, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateFontProperties(textBlock, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdatePadding(nodeToUpdate, textBlock, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateTextAlignment(textBlock, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateTextTrimming(textBlock, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateTextDecorationLine(textBlock, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateCharacterSpacing(textBlock, propertyName, propertyValue)) {
- continue;
- } else if (propertyName == "numberOfLines") {
- if (propertyValue.isNumber()) {
- auto numberLines = static_cast(propertyValue.asDouble());
- if (numberLines == 1) {
- textBlock.TextWrapping(winrt::TextWrapping::NoWrap); // setting no wrap for single line
- // text for better trimming
- // experience
- } else {
- textBlock.TextWrapping(winrt::TextWrapping::Wrap);
- }
- textBlock.MaxLines(numberLines);
- } else if (propertyValue.isNull()) {
- textBlock.TextWrapping(winrt::TextWrapping::Wrap); // set wrapping back to default
- textBlock.ClearValue(winrt::TextBlock::MaxLinesProperty());
+ return true;
+
+ if (TryUpdateForeground(textBlock, propertyName, propertyValue)) {
+ } else if (TryUpdateFontProperties(textBlock, propertyName, propertyValue)) {
+ } else if (TryUpdatePadding(nodeToUpdate, textBlock, propertyName, propertyValue)) {
+ } else if (TryUpdateTextAlignment(textBlock, propertyName, propertyValue)) {
+ } else if (TryUpdateTextTrimming(textBlock, propertyName, propertyValue)) {
+ } else if (TryUpdateTextDecorationLine(textBlock, propertyName, propertyValue)) {
+ } else if (TryUpdateCharacterSpacing(textBlock, propertyName, propertyValue)) {
+ } else if (propertyName == "numberOfLines") {
+ if (propertyValue.isNumber()) {
+ auto numberLines = static_cast(propertyValue.asDouble());
+ if (numberLines == 1) {
+ textBlock.TextWrapping(winrt::TextWrapping::NoWrap); // setting no wrap for single line
+ // text for better trimming
+ // experience
+ } else {
+ textBlock.TextWrapping(winrt::TextWrapping::Wrap);
}
- } else if (propertyName == "lineHeight") {
- if (propertyValue.isNumber())
- textBlock.LineHeight(static_cast(propertyValue.asDouble()));
- else if (propertyValue.isNull())
- textBlock.ClearValue(winrt::TextBlock::LineHeightProperty());
- } else if (propertyName == "selectable") {
- if (propertyValue.isBool())
- textBlock.IsTextSelectionEnabled(propertyValue.asBool());
- else if (propertyValue.isNull())
- textBlock.ClearValue(winrt::TextBlock::IsTextSelectionEnabledProperty());
- } else if (propertyName == "allowFontScaling") {
- if (propertyValue.isBool())
- textBlock.IsTextScaleFactorEnabled(propertyValue.asBool());
- else
- textBlock.ClearValue(winrt::TextBlock::IsTextScaleFactorEnabledProperty());
- } else if (propertyName == "selectionColor") {
- if (IsValidColorValue(propertyValue)) {
- textBlock.SelectionHighlightColor(SolidColorBrushFrom(propertyValue));
- } else
- textBlock.ClearValue(winrt::TextBlock::SelectionHighlightColorProperty());
+ textBlock.MaxLines(numberLines);
+ } else if (propertyValue.isNull()) {
+ textBlock.TextWrapping(winrt::TextWrapping::Wrap); // set wrapping back to default
+ textBlock.ClearValue(winrt::TextBlock::MaxLinesProperty());
}
+ } else if (propertyName == "lineHeight") {
+ if (propertyValue.isNumber())
+ textBlock.LineHeight(static_cast(propertyValue.asDouble()));
+ else if (propertyValue.isNull())
+ textBlock.ClearValue(winrt::TextBlock::LineHeightProperty());
+ } else if (propertyName == "selectable") {
+ if (propertyValue.isBool())
+ textBlock.IsTextSelectionEnabled(propertyValue.asBool());
+ else if (propertyValue.isNull())
+ textBlock.ClearValue(winrt::TextBlock::IsTextSelectionEnabledProperty());
+ } else if (propertyName == "allowFontScaling") {
+ if (propertyValue.isBool()) {
+ textBlock.IsTextScaleFactorEnabled(propertyValue.asBool());
+ } else {
+ textBlock.ClearValue(winrt::TextBlock::IsTextScaleFactorEnabledProperty());
+ }
+ } else if (propertyName == "selectionColor") {
+ if (IsValidColorValue(propertyValue)) {
+ textBlock.SelectionHighlightColor(SolidColorBrushFrom(propertyValue));
+ } else
+ textBlock.ClearValue(winrt::TextBlock::SelectionHighlightColorProperty());
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
-
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
void TextViewManager::AddView(XamlView parent, XamlView child, int64_t index) {
diff --git a/vnext/ReactUWP/Views/TextViewManager.h b/vnext/ReactUWP/Views/TextViewManager.h
index 01b95b937fd..6adb5eac74c 100644
--- a/vnext/ReactUWP/Views/TextViewManager.h
+++ b/vnext/ReactUWP/Views/TextViewManager.h
@@ -17,7 +17,6 @@ class TextViewManager : public FrameworkElementViewManager {
facebook::react::ShadowNode *createShadow() const override;
const char *GetName() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
void AddView(XamlView parent, XamlView child, int64_t index) override;
void RemoveAllChildren(XamlView parent) override;
@@ -28,6 +27,11 @@ class TextViewManager : public FrameworkElementViewManager {
void OnDescendantTextPropertyChanged(ShadowNodeBase *node);
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
};
diff --git a/vnext/ReactUWP/Views/ViewManagerBase.cpp b/vnext/ReactUWP/Views/ViewManagerBase.cpp
index e29e68c7f88..38feb176955 100644
--- a/vnext/ReactUWP/Views/ViewManagerBase.cpp
+++ b/vnext/ReactUWP/Views/ViewManagerBase.cpp
@@ -6,12 +6,15 @@
#include
#include "ViewPanel.h"
+#include "cdebug.h"
+#include "unicode.h"
#include
#include
#include
#include
+#include
#include
using namespace folly;
@@ -226,17 +229,28 @@ void ViewManagerBase::UpdateProperties(ShadowNodeBase *nodeToUpdate, const dynam
for (const auto &pair : reactDiffMap.items()) {
const std::string &propertyName = pair.first.getString();
const folly::dynamic &propertyValue = pair.second;
-
- if (propertyName == "onLayout") {
- nodeToUpdate->m_onLayout = !propertyValue.isNull() && propertyValue.asBool();
- } else if (propertyName == "keyDownEvents") {
- nodeToUpdate->UpdateHandledKeyboardEvents(propertyName, propertyValue);
- } else if (propertyName == "keyUpEvents") {
- nodeToUpdate->UpdateHandledKeyboardEvents(propertyName, propertyValue);
+ if (!UpdateProperty(nodeToUpdate, propertyName, propertyValue)) {
+ NotifyUnimplementedProperty(nodeToUpdate, propertyName, propertyValue);
}
}
}
+bool ViewManagerBase::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
+ if (propertyName == "onLayout") {
+ nodeToUpdate->m_onLayout = !propertyValue.isNull() && propertyValue.asBool();
+ } else if (propertyName == "keyDownEvents") {
+ nodeToUpdate->UpdateHandledKeyboardEvents(propertyName, propertyValue);
+ } else if (propertyName == "keyUpEvents") {
+ nodeToUpdate->UpdateHandledKeyboardEvents(propertyName, propertyValue);
+ } else {
+ return false;
+ }
+ return true;
+}
+
void ViewManagerBase::TransferProperties(XamlView /*oldView*/, XamlView /*newView*/) {}
void ViewManagerBase::DispatchCommand(
@@ -246,6 +260,60 @@ void ViewManagerBase::DispatchCommand(
assert(false); // View did not handle its command
}
+void ViewManagerBase::NotifyUnimplementedProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &value) {
+#ifdef DEBUG
+ auto viewManagerName = nodeToUpdate->GetViewManager()->GetName();
+ auto element(nodeToUpdate->GetView().as());
+
+ if (element != nullptr) {
+ auto className = Microsoft::Common::Unicode::Utf16ToUtf8(winrt::get_class_name(element));
+ TestHook::NotifyUnimplementedProperty(viewManagerName, className, propertyName, value);
+ } else {
+ cdebug << "[NonIInspectable] viewManagerName = " << viewManagerName << std::endl;
+ }
+#endif // DEBUG
+}
+
+#ifdef DEBUG
+
+void ViewManagerBase::TestHook::NotifyUnimplementedProperty(
+ const std::string &viewManager,
+ const std::string &reactClassName,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
+ std::string value;
+ size_t size{};
+ try {
+ if (propertyValue.isObject()) {
+ value = "[Object]";
+ } else if (propertyValue.isNull()) {
+ value = "[Null]";
+ } else if (propertyValue.isArray()) {
+ size = propertyValue.size();
+ value = "[Array]";
+ } else {
+ value = propertyValue.asString();
+ }
+ } catch (const TypeError &e) {
+ value = e.what();
+ }
+
+ cdebug << "[UnimplementedProperty] ViewManager = " << viewManager << " elementClass = " << reactClassName
+ << " propertyName = " << propertyName << " value = " << value;
+
+ if (size != 0) {
+ cdebug << " (" << size << " elems)";
+ }
+
+ cdebug << std::endl;
+ // DebugBreak();
+}
+
+#endif // DEBUG
+
void ViewManagerBase::SetLayoutProps(
ShadowNodeBase &nodeToUpdate,
XamlView viewToUpdate,
diff --git a/vnext/ReactUWP/Views/ViewViewManager.cpp b/vnext/ReactUWP/Views/ViewViewManager.cpp
index 1a19bb24260..438d98c8b1d 100644
--- a/vnext/ReactUWP/Views/ViewViewManager.cpp
+++ b/vnext/ReactUWP/Views/ViewViewManager.cpp
@@ -332,62 +332,56 @@ folly::dynamic ViewViewManager::GetNativeProps() const {
return props;
}
-void ViewViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool ViewViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto *pViewShadowNode = static_cast(nodeToUpdate);
bool shouldBeControl = pViewShadowNode->IsControl();
bool finalizeBorderRadius{false};
auto pPanel = pViewShadowNode->GetViewPanel();
-
+ bool ret = true;
if (pPanel != nullptr) {
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- if (TryUpdateBackgroundBrush(pPanel, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateBorderProperties(nodeToUpdate, pPanel, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateCornerRadiusOnNode(nodeToUpdate, pPanel, propertyName, propertyValue)) {
- finalizeBorderRadius = true;
- continue;
- } else if (TryUpdateMouseEvents(nodeToUpdate, propertyName, propertyValue)) {
- continue;
- } else if (propertyName == "onClick") {
- pViewShadowNode->OnClick(!propertyValue.isNull() && propertyValue.asBool());
- } else if (propertyName == "overflow") {
- if (propertyValue.isString()) {
- bool clipChildren = propertyValue.getString() == "hidden";
- pPanel.ClipChildren(clipChildren);
- }
- } else if (propertyName == "pointerEvents") {
- if (propertyValue.isString()) {
- bool hitTestable = propertyValue.getString() != "none";
- pPanel.IsHitTestVisible(hitTestable);
- }
- } else if (propertyName == "acceptsKeyboardFocus") {
- if (propertyValue.isBool())
- shouldBeControl = propertyValue.getBool();
- } else if (propertyName == "enableFocusRing") {
- if (propertyValue.isBool())
- pViewShadowNode->EnableFocusRing(propertyValue.getBool());
- else if (propertyValue.isNull())
- pViewShadowNode->EnableFocusRing(false);
- } else if (propertyName == "tabIndex") {
- if (propertyValue.isNumber()) {
- auto tabIndex = propertyValue.asDouble();
- if (tabIndex == static_cast(tabIndex)) {
- pViewShadowNode->TabIndex(static_cast(tabIndex));
- }
- } else if (propertyValue.isNull()) {
- pViewShadowNode->TabIndex(-1);
+ if (TryUpdateBackgroundBrush(pPanel, propertyName, propertyValue)) {
+ } else if (TryUpdateBorderProperties(nodeToUpdate, pPanel, propertyName, propertyValue)) {
+ } else if (TryUpdateCornerRadiusOnNode(nodeToUpdate, pPanel, propertyName, propertyValue)) {
+ finalizeBorderRadius = true;
+ } else if (TryUpdateMouseEvents(nodeToUpdate, propertyName, propertyValue)) {
+ } else if (propertyName == "onClick") {
+ pViewShadowNode->OnClick(!propertyValue.isNull() && propertyValue.asBool());
+ } else if (propertyName == "overflow") {
+ if (propertyValue.isString()) {
+ bool clipChildren = propertyValue.getString() == "hidden";
+ pPanel.ClipChildren(clipChildren);
+ }
+ } else if (propertyName == "pointerEvents") {
+ if (propertyValue.isString()) {
+ bool hitTestable = propertyValue.getString() != "none";
+ pPanel.IsHitTestVisible(hitTestable);
+ }
+ } else if (propertyName == "acceptsKeyboardFocus") {
+ if (propertyValue.isBool())
+ shouldBeControl = propertyValue.getBool();
+ } else if (propertyName == "enableFocusRing") {
+ if (propertyValue.isBool())
+ pViewShadowNode->EnableFocusRing(propertyValue.getBool());
+ else if (propertyValue.isNull())
+ pViewShadowNode->EnableFocusRing(false);
+ } else if (propertyName == "tabIndex") {
+ if (propertyValue.isNumber()) {
+ auto tabIndex = propertyValue.asDouble();
+ if (tabIndex == static_cast(tabIndex)) {
+ pViewShadowNode->TabIndex(static_cast(tabIndex));
}
+ } else if (propertyValue.isNull()) {
+ pViewShadowNode->TabIndex(-1);
}
+ } else {
+ ret = Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
}
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
-
if (auto view = pViewShadowNode->GetView().try_as()) {
// If we have DynamicAutomationProperties, we need a ViewControl with a
// DynamicAutomationPeer
@@ -400,6 +394,7 @@ void ViewViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly
pPanel.FinalizeProperties();
TryUpdateView(pViewShadowNode, pPanel, shouldBeControl);
+ return ret;
}
void ViewViewManager::TryUpdateView(
diff --git a/vnext/ReactUWP/Views/ViewViewManager.h b/vnext/ReactUWP/Views/ViewViewManager.h
index f197f89c6ac..4cb537bb215 100644
--- a/vnext/ReactUWP/Views/ViewViewManager.h
+++ b/vnext/ReactUWP/Views/ViewViewManager.h
@@ -27,8 +27,6 @@ class ViewViewManager : public FrameworkElementViewManager {
folly::dynamic GetExportedCustomDirectEventTypeConstants() const override;
facebook::react::ShadowNode *createShadow() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
-
// Yoga Layout
void SetLayoutProps(
ShadowNodeBase &nodeToUpdate,
@@ -39,6 +37,11 @@ class ViewViewManager : public FrameworkElementViewManager {
float height) override;
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
void TryUpdateView(ViewShadowNode *viewShadowNode, winrt::react::uwp::ViewPanel &pPanel, bool useControl);
};
diff --git a/vnext/ReactUWP/Views/VirtualTextViewManager.cpp b/vnext/ReactUWP/Views/VirtualTextViewManager.cpp
index abadf727a81..5b8f9c49b95 100644
--- a/vnext/ReactUWP/Views/VirtualTextViewManager.cpp
+++ b/vnext/ReactUWP/Views/VirtualTextViewManager.cpp
@@ -33,29 +33,24 @@ XamlView VirtualTextViewManager::CreateViewCore(int64_t /*tag*/) {
return winrt::Span();
}
-void VirtualTextViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
+bool VirtualTextViewManager::UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) {
auto span = nodeToUpdate->GetView().as();
if (span == nullptr)
- return;
-
- for (const auto &pair : reactDiffMap.items()) {
- const std::string &propertyName = pair.first.getString();
- const folly::dynamic &propertyValue = pair.second;
-
- // FUTURE: In the future cppwinrt will generate code where static methods on
- // base types can be called. For now we specify the base type explicitly
- if (TryUpdateForeground(span, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateFontProperties(span, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateCharacterSpacing(span, propertyName, propertyValue)) {
- continue;
- } else if (TryUpdateTextDecorationLine(span, propertyName, propertyValue)) {
- continue;
- }
+ return true;
+
+ // FUTURE: In the future cppwinrt will generate code where static methods on
+ // base types can be called. For now we specify the base type explicitly
+ if (TryUpdateForeground(span, propertyName, propertyValue)) {
+ } else if (TryUpdateFontProperties(span, propertyName, propertyValue)) {
+ } else if (TryUpdateCharacterSpacing(span, propertyName, propertyValue)) {
+ } else if (TryUpdateTextDecorationLine(span, propertyName, propertyValue)) {
+ } else {
+ return Super::UpdateProperty(nodeToUpdate, propertyName, propertyValue);
}
-
- Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+ return true;
}
void VirtualTextViewManager::AddView(XamlView parent, XamlView child, int64_t index) {
diff --git a/vnext/ReactUWP/Views/VirtualTextViewManager.h b/vnext/ReactUWP/Views/VirtualTextViewManager.h
index 26d9d5f2df8..4881f429cfc 100644
--- a/vnext/ReactUWP/Views/VirtualTextViewManager.h
+++ b/vnext/ReactUWP/Views/VirtualTextViewManager.h
@@ -15,7 +15,6 @@ class VirtualTextViewManager : public ViewManagerBase {
VirtualTextViewManager(const std::shared_ptr &reactInstance);
const char *GetName() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
void AddView(XamlView parent, XamlView child, int64_t index) override;
void RemoveAllChildren(XamlView parent) override;
@@ -24,6 +23,11 @@ class VirtualTextViewManager : public ViewManagerBase {
bool RequiresYogaNode() const override;
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
XamlView CreateViewCore(int64_t tag) override;
};
diff --git a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj
index 582f47afc90..33d57837c25 100644
--- a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj
+++ b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj
@@ -173,6 +173,7 @@
+
@@ -238,4 +239,4 @@
-
+
\ No newline at end of file
diff --git a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters
index e6204ac0b12..fd860c6c427 100644
--- a/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters
+++ b/vnext/ReactWindowsCore/ReactWindowsCore.vcxproj.filters
@@ -114,6 +114,9 @@
Source Files
+
+ Source Files
+
diff --git a/vnext/ReactWindowsCore/cdebug.cpp b/vnext/ReactWindowsCore/cdebug.cpp
new file mode 100644
index 00000000000..794f5188e6e
--- /dev/null
+++ b/vnext/ReactWindowsCore/cdebug.cpp
@@ -0,0 +1,4 @@
+#include "cdebug.h"
+
+basic_dostream cdebug;
+basic_dostream cwdebug;
diff --git a/vnext/include/Include.vcxitems b/vnext/include/Include.vcxitems
index 194a9dbe378..4c2f792e6c0 100644
--- a/vnext/include/Include.vcxitems
+++ b/vnext/include/Include.vcxitems
@@ -39,6 +39,7 @@
+
diff --git a/vnext/include/Include.vcxitems.filters b/vnext/include/Include.vcxitems.filters
index 9e5b13ff3fd..7752ef2e130 100644
--- a/vnext/include/Include.vcxitems.filters
+++ b/vnext/include/Include.vcxitems.filters
@@ -20,6 +20,9 @@
ReactUWP
+
+ ReactWindowsCore
+
ReactWindowsCore
diff --git a/vnext/include/ReactUWP/Views/ControlViewManager.h b/vnext/include/ReactUWP/Views/ControlViewManager.h
index 72f6c14eba0..0d1c4949eae 100644
--- a/vnext/include/ReactUWP/Views/ControlViewManager.h
+++ b/vnext/include/ReactUWP/Views/ControlViewManager.h
@@ -17,7 +17,10 @@ class REACTWINDOWS_EXPORT ControlViewManager : public FrameworkElementViewManage
ControlViewManager(const std::shared_ptr &reactInstance);
folly::dynamic GetNativeProps() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
void TransferProperties(XamlView oldView, XamlView newView) override;
protected:
diff --git a/vnext/include/ReactUWP/Views/FrameworkElementViewManager.h b/vnext/include/ReactUWP/Views/FrameworkElementViewManager.h
index 891afa8d6c1..0bf111a8183 100644
--- a/vnext/include/ReactUWP/Views/FrameworkElementViewManager.h
+++ b/vnext/include/ReactUWP/Views/FrameworkElementViewManager.h
@@ -16,7 +16,6 @@ class REACTWINDOWS_EXPORT FrameworkElementViewManager : public ViewManagerBase {
FrameworkElementViewManager(const std::shared_ptr &reactInstance);
folly::dynamic GetNativeProps() const override;
- void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) override;
// Helper functions related to setting/updating TransformMatrix
void RefreshTransformMatrix(ShadowNodeBase *shadowNode);
@@ -27,6 +26,11 @@ class REACTWINDOWS_EXPORT FrameworkElementViewManager : public ViewManagerBase {
virtual void TransferProperties(XamlView oldView, XamlView newView) override;
protected:
+ bool UpdateProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue) override;
+
void TransferProperty(XamlView oldView, XamlView newView, winrt::Windows::UI::Xaml::DependencyProperty dp);
void TransferProperty(
diff --git a/vnext/include/ReactUWP/Views/ViewManagerBase.h b/vnext/include/ReactUWP/Views/ViewManagerBase.h
index bb1fc6b06a0..17f2e2ae6c0 100644
--- a/vnext/include/ReactUWP/Views/ViewManagerBase.h
+++ b/vnext/include/ReactUWP/Views/ViewManagerBase.h
@@ -80,7 +80,21 @@ class REACTWINDOWS_EXPORT ViewManagerBase : public facebook::react::IViewManager
protected:
virtual XamlView CreateViewCore(int64_t tag) = 0;
virtual void OnViewCreated(XamlView view){};
-
+ virtual bool
+ UpdateProperty(ShadowNodeBase *nodeToUpdate, const std::string &propertyName, const folly::dynamic &propertyValue);
+ virtual void NotifyUnimplementedProperty(
+ ShadowNodeBase *nodeToUpdate,
+ const std::string &propertyName,
+ const folly::dynamic &value);
+#ifdef DEBUG
+ struct TestHook {
+ static void NotifyUnimplementedProperty(
+ const std::string &viewManager,
+ const std::string &reactClassName,
+ const std::string &propertyName,
+ const folly::dynamic &propertyValue);
+ };
+#endif
protected:
std::weak_ptr m_wkReactInstance;
};
diff --git a/vnext/include/ReactWindowsCore/cdebug.h b/vnext/include/ReactWindowsCore/cdebug.h
new file mode 100644
index 00000000000..942db2420d8
--- /dev/null
+++ b/vnext/include/ReactWindowsCore/cdebug.h
@@ -0,0 +1,37 @@
+#pragma once
+#include
+#include
+#include
+
+template
+struct debugbuffer_t : public std::basic_stringbuf> {
+ virtual ~debugbuffer_t() {
+ sync();
+ }
+
+ virtual int sync() override {
+ _OutputDebugString(this->str().c_str());
+ this->str(std::basic_string());
+ return 0;
+ }
+
+ private:
+ void _OutputDebugString(PCSTR str) {
+ ::OutputDebugStringA(str);
+ }
+ void _OutputDebugString(PCWSTR str) {
+ ::OutputDebugStringW(str);
+ }
+};
+
+template
+class basic_dostream : public std::basic_ostream {
+ public:
+ basic_dostream() : std::basic_ostream(new debugbuffer_t()) {}
+ ~basic_dostream() {
+ delete this->rdbuf();
+ }
+};
+
+extern basic_dostream cdebug;
+extern basic_dostream cwdebug;