diff --git a/.ado/templates/e2e-test-job.yml b/.ado/templates/e2e-test-job.yml
index 3a79cfaecd4..b6e61d42af7 100644
--- a/.ado/templates/e2e-test-job.yml
+++ b/.ado/templates/e2e-test-job.yml
@@ -96,6 +96,21 @@ jobs:
script: yarn run test
workingDirectory: packages/E2ETest
+ - task: CopyFiles@2
+ displayName: Copy tree dump output files
+ inputs:
+ sourceFolder: $(LocalAppData)\Packages\ReactUWPTestApp_kc2bncckyf4ap\LocalState
+ targetFolder: $(Build.StagingDirectory)/ReactUWPTestAppTreeDump
+ contents: TreeDump\**
+ condition: succeededOrFailed()
+
+ - task: PublishBuildArtifacts@1
+ displayName: "Publish Artifact:ReactUWPTestAppTreeDump"
+ inputs:
+ artifactName: ReactUWPTestAppTreeDump
+ pathtoPublish: $(Build.StagingDirectory)/ReactUWPTestAppTreeDump
+ condition: succeededOrFailed()
+
- task: PublishTestResults@2
inputs:
testResultsFormat: "JUnit"
diff --git a/change/react-native-windows-2019-12-10-12-31-34-treedump.json b/change/react-native-windows-2019-12-10-12-31-34-treedump.json
new file mode 100644
index 00000000000..14cfc4b5c6f
--- /dev/null
+++ b/change/react-native-windows-2019-12-10-12-31-34-treedump.json
@@ -0,0 +1,8 @@
+{
+ "type": "prerelease",
+ "comment": "TreeDump for E2E test and fix for image border issue",
+ "packageName": "react-native-windows",
+ "email": "dida@ntdev.microsoft.com",
+ "commit": "88f9b0eaecfe88e2243b66d969420131224f1c56",
+ "date": "2019-12-10T20:31:33.939Z"
+}
\ No newline at end of file
diff --git a/packages/E2ETest/app/Consts.ts b/packages/E2ETest/app/Consts.ts
index c6e0246d04a..d8f29264284 100644
--- a/packages/E2ETest/app/Consts.ts
+++ b/packages/E2ETest/app/Consts.ts
@@ -4,6 +4,7 @@ export const APP_NAME = 'ReactUWPTestApp';
export const SEARCH_BUTTON = 'SearchButton';
export const HOME_BUTTON = '_HomeButton';
export const REACT_CONTROL_ERROR_TEST_ID = 'ReactControlErrorMessage';
+export const TREE_DUMP_RESULT = 'TreeDump';
// UnknownTestPage
export const UNKNOWN_TESTPAGE = 'UnknownTestPage';
@@ -31,3 +32,9 @@ export const ACCESSBILITY_TESTPAGE = 'AccessiblityTestPage';
export const DIRECT_MANIPULATION_TESTPAGE = 'DirectManipulationTestPage';
export const MEASURE_IN_WINDOW_BUTTON = 'MeasureInWindow';
export const MEASURE_IN_WINDOW_RESULT = 'MeasureInWindowResult';
+
+// Image Test Page
+export const IMAGE_TESTPAGE = 'ImageTestPage';
+export const IMAGE_CHANGE_BORDER = 'ChangeBorder';
+export const SHOW_IMAGE_BORDER = 'BorderButton';
+export const IMAGE_CONTAINER = 'ImageContainer';
diff --git a/packages/E2ETest/app/ImageTestPage.tsx b/packages/E2ETest/app/ImageTestPage.tsx
new file mode 100644
index 00000000000..3ca2d302647
--- /dev/null
+++ b/packages/E2ETest/app/ImageTestPage.tsx
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+
+import {StyleSheet, View, Image, Button, requireNativeComponent} from 'react-native'
+import React, { useState } from 'react';
+import { TREE_DUMP_RESULT, SHOW_IMAGE_BORDER, IMAGE_CONTAINER } from './Consts';
+const TreeDumpControl = requireNativeComponent('TreeDumpControl');
+
+const styles = StyleSheet.create({
+ container: {
+ height:300,
+ width:500,
+ backgroundColor: 'yellow',
+ alignItems:'center',
+ },
+ containerWithBorder: {
+ height:300,
+ width:500,
+ borderRadius: 10.0,
+ borderWidth:10,
+ borderColor: '#00ff0055',
+ backgroundColor: 'yellow',
+ alignItems:'center',
+ },
+ imageWithBorder: {
+ height: '100%',
+ width: '100%',
+ borderRadius: 10.0,
+ borderWidth:10,
+ borderColor: '#0000ff55',
+ backgroundColor: 'red',
+ },
+ image: {
+ height: '100%',
+ width: '100%',
+ backgroundColor: 'red',
+ },
+ treeDumpControl: {
+ height: 150,
+ width: 500,
+ margin: 10,
+ },
+});
+
+export function ImageTestPage() {
+ const [imageWithBorder, setImageBorder] = useState(false);
+ const [clickCount, setClickCount] = useState(0);
+ const onPressBorder = () => {
+ var previousImageBorderState = imageWithBorder;
+ setImageBorder(!previousImageBorderState);
+ var previousClickCount = clickCount;
+ setClickCount(previousClickCount+1);
+ }
+ return(
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/packages/E2ETest/app/TestPages.ts b/packages/E2ETest/app/TestPages.ts
index ec1f4b1da03..5973e8af428 100644
--- a/packages/E2ETest/app/TestPages.ts
+++ b/packages/E2ETest/app/TestPages.ts
@@ -13,10 +13,12 @@ import {
LOGIN_TESTPAGE,
ACCESSBILITY_TESTPAGE,
DIRECT_MANIPULATION_TESTPAGE,
+ IMAGE_TESTPAGE,
} from './Consts';
import { LoginTestPage } from './LoginTestPage';
import { AccessibilityTestPage } from './AccessibilityTestPage';
import { DirectManipulationTestPage } from './DirectManipulationPage';
+import { ImageTestPage } from './ImageTestPage';
export interface ITestPage {
testId: string;
@@ -45,6 +47,11 @@ const TestPages: ITestPage[] = [
description: 'Direct Manipulation Test Page',
content: DirectManipulationTestPage,
},
+ {
+ testId: IMAGE_TESTPAGE,
+ description: 'Image Test Page',
+ content: ImageTestPage,
+ },
{
testId: UNKNOWN_TESTPAGE,
description: 'Unknown Page',
diff --git a/packages/E2ETest/wdio/pages/BasePage.ts b/packages/E2ETest/wdio/pages/BasePage.ts
index 924d14f5128..8d346c428c2 100644
--- a/packages/E2ETest/wdio/pages/BasePage.ts
+++ b/packages/E2ETest/wdio/pages/BasePage.ts
@@ -2,12 +2,22 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
-import { REACT_CONTROL_ERROR_TEST_ID, HOME_BUTTON } from '../../app/Consts';
+import {
+ REACT_CONTROL_ERROR_TEST_ID,
+ HOME_BUTTON,
+ TREE_DUMP_RESULT,
+} from '../../app/Consts';
export function By(testId: string): WebdriverIO.Element {
return $('~' + testId);
}
+export function wait(timeout: number) {
+ return new Promise(resolve => {
+ setTimeout(resolve, timeout);
+ });
+}
+
export class BasePage {
isPageLoaded(): boolean {
return this.homeButton.isDisplayed();
@@ -23,6 +33,28 @@ export class BasePage {
);
}
+ getTreeDumpResult() {
+ var testResult = false;
+ const maxWait = 20;
+ var waitCount = 1;
+ do {
+ testResult = this.treeDumpResult.getText() == 'TreeDump:Passed';
+ if (!testResult) {
+ console.log(
+ '####Waiting for treedump comparison result ' +
+ waitCount +
+ '/' +
+ maxWait +
+ '...####'
+ );
+ wait(100);
+ waitCount += 1;
+ }
+ } while (waitCount <= maxWait && !testResult);
+
+ return testResult;
+ }
+
protected timeoutForPageLoaded(currentTimeout?: number) {
if (currentTimeout) return currentTimeout;
return this.waitforPageTimeout;
@@ -44,6 +76,10 @@ export class BasePage {
return this.isPageLoaded();
}
+ private get treeDumpResult() {
+ return By(TREE_DUMP_RESULT);
+ }
+
// Default timeout for waitForPageLoaded command in PageObject
private waitforPageTimeout: number = 10000;
}
diff --git a/packages/E2ETest/wdio/pages/HomePage.ts b/packages/E2ETest/wdio/pages/HomePage.ts
index 74d297716a4..ae7026e3ef3 100644
--- a/packages/E2ETest/wdio/pages/HomePage.ts
+++ b/packages/E2ETest/wdio/pages/HomePage.ts
@@ -9,9 +9,11 @@ import {
TEXTINPUT_TESTPAGE,
LOGIN_TESTPAGE,
DIRECT_MANIPULATION_TESTPAGE,
+ IMAGE_TESTPAGE,
} from '../../app/Consts';
import LoginPage from './LoginPage';
import DirectManipulationPage from './DirectManipulationPage';
+import ImageTestPage from './ImageTestPage';
class HomePage extends BasePage {
backToHomePage() {
@@ -38,6 +40,11 @@ class HomePage extends BasePage {
DirectManipulationPage.waitForPageLoaded();
}
+ clickAndGotoImagePage() {
+ this.ImagePageButton.click();
+ ImageTestPage.waitForPageLoaded();
+ }
+
private get testInputTestPageButton() {
return By(TEXTINPUT_TESTPAGE);
}
@@ -49,6 +56,10 @@ class HomePage extends BasePage {
private get directManipulationPageButton() {
return By(DIRECT_MANIPULATION_TESTPAGE);
}
+
+ private get ImagePageButton() {
+ return By(IMAGE_TESTPAGE);
+ }
}
export default new HomePage();
diff --git a/packages/E2ETest/wdio/pages/ImageTestPage.ts b/packages/E2ETest/wdio/pages/ImageTestPage.ts
new file mode 100644
index 00000000000..a596d277fc7
--- /dev/null
+++ b/packages/E2ETest/wdio/pages/ImageTestPage.ts
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+
+import { BasePage, By } from './BasePage';
+import { SHOW_IMAGE_BORDER } from '../../app/Consts';
+
+class ImageTestPage extends BasePage {
+ backToHomePage() {
+ this.homeButton.click();
+ this.waitForPageLoaded();
+ }
+
+ isPageLoaded() {
+ return super.isPageLoaded();
+ }
+
+ toggleImageBorder() {
+ this._imageBorder.click();
+ }
+
+ private get _imageBorder() {
+ return By(SHOW_IMAGE_BORDER);
+ }
+}
+
+export default new ImageTestPage();
diff --git a/packages/E2ETest/wdio/test/Image.spec.ts b/packages/E2ETest/wdio/test/Image.spec.ts
new file mode 100644
index 00000000000..46844600373
--- /dev/null
+++ b/packages/E2ETest/wdio/test/Image.spec.ts
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License.
+ */
+
+import HomePage from '../pages/HomePage';
+import ImageTestPage from '../pages/ImageTestPage';
+import assert from 'assert';
+
+beforeAll(() => {
+ HomePage.backToHomePage();
+ HomePage.clickAndGotoImagePage();
+});
+
+describe('ImageWithoutBorderTest', () => {
+ /* Test case #1: view and image displayed with no border and cornerRadius */
+ it('ImageWithoutBorderTest', () => {
+ const result = ImageTestPage.getTreeDumpResult();
+ assert(result, '#1. Dump comparison for image without border!');
+ });
+
+ /* Test case #2: Click button once, update view and image with round border*/
+ it('ImageWithBorderTest', () => {
+ ImageTestPage.toggleImageBorder();
+ const result = ImageTestPage.getTreeDumpResult();
+ assert(result, '#2. Dump comparison for image with border!');
+ });
+
+/* Test case #3: Click button one more, remove border from view and image but tree sturcture is different from #1*/
+ it('ImageWithoutBorderTest', () => {
+ ImageTestPage.toggleImageBorder();
+ const result = ImageTestPage.getTreeDumpResult();
+ assert(result, '#3. Second dump comparison for image without border!');
+ });
+});
diff --git a/packages/E2ETest/windows/ReactUWPTestApp.sln b/packages/E2ETest/windows/ReactUWPTestApp.sln
index 72a6b2edf8a..3be1239de1e 100644
--- a/packages/E2ETest/windows/ReactUWPTestApp.sln
+++ b/packages/E2ETest/windows/ReactUWPTestApp.sln
@@ -44,6 +44,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.ReactNative.SharedManaged", "..\..\..\vnext\Microsoft.ReactNative.SharedManaged\Microsoft.ReactNative.SharedManaged.shproj", "{67A1076F-7790-4203-86EA-4402CCB5E782}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeDumpLibrary", "TreeDumpLibrary\TreeDumpLibrary.csproj", "{C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
..\..\..\vnext\Chakra\Chakra.vcxitems*{2d5d43d9-cffc-4c40-b4cd-02efb4e2742b}*SharedItemsImports = 4
@@ -51,6 +53,7 @@ Global
..\..\..\vnext\Microsoft.ReactNative.SharedManaged\Microsoft.ReactNative.SharedManaged.projitems*{67a1076f-7790-4203-86ea-4402ccb5e782}*SharedItemsImports = 13
..\..\..\vnext\JSI\Shared\JSI.Shared.vcxitems*{a62d504a-16b8-41d2-9f19-e2e86019e5e4}*SharedItemsImports = 4
..\..\..\vnext\Microsoft.ReactNative.SharedManaged\Microsoft.ReactNative.SharedManaged.projitems*{abbb0407-0e82-486f-94ce-710900fcaadc}*SharedItemsImports = 4
+ ..\..\..\vnext\Microsoft.ReactNative.SharedManaged\Microsoft.ReactNative.SharedManaged.projitems*{c0a6bd9c-3ee5-4b12-8ce4-cee95178539c}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
@@ -163,6 +166,18 @@ Global
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x64.Build.0 = Release|x64
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.ActiveCfg = Release|Win32
{F7D32BD0-2749-483E-9A0D-1635EF7E3136}.Release|x86.Build.0 = Release|Win32
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Debug|ARM.ActiveCfg = Debug|ARM
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Debug|ARM.Build.0 = Debug|ARM
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Debug|x64.ActiveCfg = Debug|x64
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Debug|x64.Build.0 = Debug|x64
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Debug|x86.ActiveCfg = Debug|x86
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Debug|x86.Build.0 = Debug|x86
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Release|ARM.ActiveCfg = Release|ARM
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Release|ARM.Build.0 = Release|ARM
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Release|x64.ActiveCfg = Release|x64
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Release|x64.Build.0 = Release|x64
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Release|x86.ActiveCfg = Release|x86
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/packages/E2ETest/windows/ReactUWPTestApp/App.xaml.cs b/packages/E2ETest/windows/ReactUWPTestApp/App.xaml.cs
index 16d3716cf67..3bc2c40c71d 100644
--- a/packages/E2ETest/windows/ReactUWPTestApp/App.xaml.cs
+++ b/packages/E2ETest/windows/ReactUWPTestApp/App.xaml.cs
@@ -9,6 +9,8 @@
using Windows.UI.Xaml.Navigation;
using Microsoft.ReactNative;
using Windows.UI.Core;
+using Windows.UI.ViewManagement;
+using Windows.Foundation;
namespace ReactUWPTestApp
{
@@ -42,6 +44,8 @@ public App()
#endif
PackageProviders.Add(new Microsoft.ReactNative.Managed.ReactPackageProvider()); // Includes any modules in this project
+ PackageProviders.Add(new TreeDumpLibrary.ReactPackageProvider());
+
this.InitializeComponent();
}
@@ -54,6 +58,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
{
base.OnLaunched(e);
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = AppViewBackButtonVisibility.Collapsed;
+ ApplicationView.GetForCurrentView().TryResizeView(new Size(800, 600));
}
}
}
diff --git a/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithBorder.txt b/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithBorder.txt
new file mode 100644
index 00000000000..6e29f528cdc
--- /dev/null
+++ b/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithBorder.txt
@@ -0,0 +1,26 @@
+[Windows.UI.Xaml.Controls.Border]
+ Background=#FFFFFF00
+ BorderBrush=#5500FF00
+ BorderThickness=10,10,10,10
+ Clip=[NULL]
+ CornerRadius=10,10,10,10
+ Height=300
+ HorizontalAlignment=Stretch
+ Margin=0,0,0,0
+ Padding=0,0,0,0
+ RenderSize=500,300
+ VerticalAlignment=Stretch
+ Visibility=Visible
+ Width=500
+ [react.uwp.ViewPanel]
+ Background=[NULL]
+ BorderBrush=#5500FF00
+ BorderThickness=10,10,10,10
+ Clip=[NULL]
+ CornerRadius=10,10,10,10
+ HorizontalAlignment=Stretch
+ Margin=0,0,0,0
+ RenderSize=480,280
+ VerticalAlignment=Stretch
+ Visibility=Visible
+ [Windows.UI.Xaml.DependencyObject]
diff --git a/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithoutBorder-Subsequent.txt b/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithoutBorder-Subsequent.txt
new file mode 100644
index 00000000000..b4f487dba0a
--- /dev/null
+++ b/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithoutBorder-Subsequent.txt
@@ -0,0 +1,26 @@
+[Windows.UI.Xaml.Controls.Border]
+ Background=#FFFFFF00
+ BorderBrush=[NULL]
+ BorderThickness=0,0,0,0
+ Clip=[NULL]
+ CornerRadius=0,0,0,0
+ Height=300
+ HorizontalAlignment=Stretch
+ Margin=0,0,0,0
+ Padding=0,0,0,0
+ RenderSize=500,300
+ VerticalAlignment=Stretch
+ Visibility=Visible
+ Width=500
+ [react.uwp.ViewPanel]
+ Background=[NULL]
+ BorderBrush=#00000000
+ BorderThickness=0,0,0,0
+ Clip=[NULL]
+ CornerRadius=0,0,0,0
+ HorizontalAlignment=Stretch
+ Margin=0,0,0,0
+ RenderSize=500,300
+ VerticalAlignment=Stretch
+ Visibility=Visible
+ [Windows.UI.Xaml.DependencyObject]
diff --git a/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithoutBorder.txt b/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithoutBorder.txt
new file mode 100644
index 00000000000..7778ee0148f
--- /dev/null
+++ b/packages/E2ETest/windows/ReactUWPTestApp/Assets/TreeDump/ImageWithoutBorder.txt
@@ -0,0 +1,14 @@
+[react.uwp.ViewPanel]
+ Background=#FFFFFF00
+ BorderBrush=#00000000
+ BorderThickness=0,0,0,0
+ Clip=[NULL]
+ CornerRadius=0,0,0,0
+ Height=300
+ HorizontalAlignment=Stretch
+ Margin=0,0,0,0
+ RenderSize=500,300
+ VerticalAlignment=Stretch
+ Visibility=Visible
+ Width=500
+ [Windows.UI.Xaml.DependencyObject]
diff --git a/packages/E2ETest/windows/ReactUWPTestApp/Properties/Default.rd.xml b/packages/E2ETest/windows/ReactUWPTestApp/Properties/Default.rd.xml
index af00722cdf9..c6cf5c5ce9f 100644
--- a/packages/E2ETest/windows/ReactUWPTestApp/Properties/Default.rd.xml
+++ b/packages/E2ETest/windows/ReactUWPTestApp/Properties/Default.rd.xml
@@ -22,10 +22,10 @@
the application package. The asterisks are not wildcards.
-->
-
-
+
+
-
\ No newline at end of file
+
diff --git a/packages/E2ETest/windows/ReactUWPTestApp/ReactUWPTestApp.csproj b/packages/E2ETest/windows/ReactUWPTestApp/ReactUWPTestApp.csproj
index 37071e39d51..b88ff66c011 100644
--- a/packages/E2ETest/windows/ReactUWPTestApp/ReactUWPTestApp.csproj
+++ b/packages/E2ETest/windows/ReactUWPTestApp/ReactUWPTestApp.csproj
@@ -108,6 +108,9 @@
+
+
+
@@ -139,6 +142,10 @@
{f7d32bd0-2749-483e-9a0d-1635ef7e3136}
Microsoft.ReactNative
+
+ {c0a6bd9c-3ee5-4b12-8ce4-cee95178539c}
+ TreeDumpLibrary
+
diff --git a/packages/E2ETest/windows/ReactUWPTestApp/copyTreeDump.cmd b/packages/E2ETest/windows/ReactUWPTestApp/copyTreeDump.cmd
new file mode 100644
index 00000000000..93578825c21
--- /dev/null
+++ b/packages/E2ETest/windows/ReactUWPTestApp/copyTreeDump.cmd
@@ -0,0 +1 @@
+copy %LocalAppData%\Packages\ReactUWPTestApp_kc2bncckyf4ap\LocalState\TreeDump\*.out Assets\TreeDump\*.txt
\ No newline at end of file
diff --git a/packages/E2ETest/windows/TreeDumpLibrary/ReactPackageProvider.cs b/packages/E2ETest/windows/TreeDumpLibrary/ReactPackageProvider.cs
new file mode 100644
index 00000000000..54dccd72e3b
--- /dev/null
+++ b/packages/E2ETest/windows/TreeDumpLibrary/ReactPackageProvider.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.ReactNative.Bridge;
+using Microsoft.ReactNative.Managed;
+
+namespace TreeDumpLibrary
+{
+ public sealed class ReactPackageProvider : IReactPackageProvider
+ {
+ public void CreatePackage(IReactPackageBuilder packageBuilder)
+ {
+ packageBuilder.AddViewManagers();
+ }
+ }
+}
diff --git a/packages/E2ETest/windows/TreeDumpLibrary/TreeDumpControlViewManager.cs b/packages/E2ETest/windows/TreeDumpLibrary/TreeDumpControlViewManager.cs
new file mode 100644
index 00000000000..5b4d7eb78ef
--- /dev/null
+++ b/packages/E2ETest/windows/TreeDumpLibrary/TreeDumpControlViewManager.cs
@@ -0,0 +1,234 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Diagnostics;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Controls;
+
+using Microsoft.ReactNative.Managed;
+using Microsoft.ReactNative.Bridge;
+using Windows.UI.Xaml;
+using Windows.UI.ViewManagement;
+using System.Threading.Tasks;
+using System;
+using System.IO;
+using Windows.Storage;
+using System.Collections.Generic;
+
+namespace TreeDumpLibrary
+{
+ internal class TreeDumpControlViewManager : IViewManager, IViewManagerWithNativeProperties
+ {
+ public string Name => "TreeDumpControl";
+
+ public FrameworkElement CreateView()
+ {
+ m_textBlock = new TextBlock();
+ m_textBlock.TextWrapping = TextWrapping.Wrap;
+ m_textBlock.IsTextSelectionEnabled = false;
+ m_textBlock.LayoutUpdated += async (source, e) =>
+ {
+ var bounds = ApplicationView.GetForCurrentView().VisibleBounds;
+ if (bounds.Width != 800 || bounds.Height != 600)
+ {
+ // Dump disabled when window size is not 800x600!
+ UpdateResult(false /*matchDump*/, "Window has been resized, dump comparison is only valid at default launch size: 800x600!, current size:" + bounds.ToString());
+ }
+ else
+ {
+ await MatchTreeDumpFromLayoutUpdateAsync();
+ }
+ };
+
+ m_textBlock.PointerPressed += (soruce, e) =>
+ {
+ if (!m_matchDump)
+ {
+ m_errStringShowing = true;
+ m_textBlock.Text = m_errString;
+ m_textBlock.IsTextSelectionEnabled = true;
+ }
+ };
+
+ return m_textBlock;
+ }
+
+ public void UpdateProperties(FrameworkElement view, IReadOnlyDictionary propertyMap)
+ {
+ foreach (KeyValuePair kvp in propertyMap)
+ {
+ if (kvp.Key == "dumpID")
+ {
+ SetDumpID((TextBlock)view, (string)kvp.Value);
+ }
+ else if (kvp.Key == "uiaID")
+ {
+ SetUIAID((TextBlock)view, (string)kvp.Value);
+ }
+ }
+ }
+
+ IReadOnlyDictionary IViewManagerWithNativeProperties.NativeProps
+ {
+ get
+ {
+ return new Dictionary
+ {
+ { "dumpID", ViewManagerPropertyType.String },
+ { "uiaID", ViewManagerPropertyType.String }
+ };
+ }
+ }
+
+ public void SetDumpID(TextBlock view, string value)
+ {
+ m_dumpID = value;
+ m_matchDump = false;
+ m_dumpExpectedText = null;
+ m_errString = "";
+ m_errStringShowing = false;
+ if (m_textBlock != null)
+ {
+ m_textBlock.IsTextSelectionEnabled = false;
+ }
+ }
+
+ public void SetUIAID(TextBlock view, string value)
+ {
+ m_uiaID = value;
+ }
+
+ private DependencyObject FindChildWithMatchingUIAID(DependencyObject element)
+ {
+ string automationId = (string)element.GetValue(Windows.UI.Xaml.Automation.AutomationProperties.AutomationIdProperty);
+ if (automationId == m_uiaID)
+ {
+ return element;
+ }
+ int childrenCount = VisualTreeHelper.GetChildrenCount(element);
+ for (int i = 0; i < childrenCount; i++)
+ {
+ var result = FindChildWithMatchingUIAID(VisualTreeHelper.GetChild(element, i));
+ if (result != null)
+ {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ private async Task MatchTreeDumpFromLayoutUpdateAsync()
+ {
+ // First find root
+ DependencyObject current = m_textBlock;
+ DependencyObject parent = VisualTreeHelper.GetParent(current);
+ while (parent != null)
+ {
+ current = parent;
+ parent = VisualTreeHelper.GetParent(current);
+ }
+
+ DependencyObject dumpRoot = current;
+ // if UIAID is passed in from test, find the matching child as the root to dump
+ if (m_uiaID != null)
+ {
+ var matchingNode = FindChildWithMatchingUIAID(current);
+ if (matchingNode != null)
+ {
+ dumpRoot = matchingNode;
+ }
+ }
+
+ String dumpText = VisualTreeDumper.DumpTree(dumpRoot, m_textBlock /* exclude */);
+ if (dumpText != m_dumpExpectedText)
+ {
+ await MatchDump(dumpText);
+ }
+ }
+
+ private async Task MatchDump(string dumpText)
+ {
+ if (m_dumpExpectedText == null)
+ {
+ try
+ {
+ var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(@"Assets\TreeDump\" + m_dumpID + ".txt");
+ m_dumpExpectedText = await Windows.Storage.FileIO.ReadTextAsync(file);
+
+ StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
+ string copyFileName = "TreeDump\\" + m_dumpID + ".txt";
+ var copyDumpFile = await storageFolder.CreateFileAsync(copyFileName, CreationCollisionOption.ReplaceExisting);
+ await Windows.Storage.FileIO.WriteTextAsync(copyDumpFile, m_dumpExpectedText);
+ }
+ catch (IOException)
+ {
+ UpdateResult(false /*matchDump*/, "Tree dump master file not found in testapp package!");
+ }
+ }
+
+ if (m_dumpExpectedText != dumpText)
+ {
+ StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
+ string fileName = "TreeDump\\" + m_dumpID + ".out";
+ try
+ {
+ StorageFile outFile = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
+ await Windows.Storage.FileIO.WriteTextAsync(outFile, dumpText);
+ UpdateResult(false /*matchDump*/, "Tree dump file does not match master! See output at " + outFile.Path);
+ }
+ catch (IOException)
+ {
+ UpdateResult(false /*matchDump*/, "Can't write dump output file:" + fileName);
+ }
+ }
+ else
+ {
+ UpdateResult(true /*matchDump*/, "");
+ }
+ }
+
+ private async void UpdateResult(bool matchDump, string helpText)
+ {
+ if (matchDump)
+ {
+ UpdateTextBlockText("TreeDump:Passed");
+ }
+ else
+ {
+ UpdateTextBlockText("TreeDump:Failed, click to see more!");
+ m_errString += "\r\n" + helpText;
+
+ StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
+ string fileNameError = "TreeDump\\" + m_dumpID + ".err";
+ try
+ {
+ StorageFile errFile = await storageFolder.CreateFileAsync(fileNameError, CreationCollisionOption.GenerateUniqueName);
+ await Windows.Storage.FileIO.WriteTextAsync(errFile, m_errString);
+ }
+ catch (Exception e)
+ {
+ UpdateTextBlockText("Creat err file failed: " + e.ToString());
+ }
+ }
+
+ m_matchDump = matchDump;
+ }
+
+ private void UpdateTextBlockText(string text)
+ {
+ if (!m_errStringShowing && m_textBlock.Text != text)
+ {
+ m_textBlock.Text = text;
+ }
+ }
+ private TextBlock m_textBlock = null;
+ private string m_dumpID = "UnknownTest";
+ private string m_dumpExpectedText;
+ private bool m_matchDump = false;
+ private bool m_errStringShowing = false;
+ private string m_errString = "";
+ private string m_uiaID = null;
+
+ }
+}
diff --git a/packages/E2ETest/windows/TreeDumpLibrary/TreeDumpLibrary.csproj b/packages/E2ETest/windows/TreeDumpLibrary/TreeDumpLibrary.csproj
new file mode 100644
index 00000000000..35a6c334c05
--- /dev/null
+++ b/packages/E2ETest/windows/TreeDumpLibrary/TreeDumpLibrary.csproj
@@ -0,0 +1,120 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {C0A6BD9C-3EE5-4B12-8CE4-CEE95178539C}
+ winmdobj
+ Properties
+ TreeDumpLibrary
+ TreeDumpLibrary
+ en-US
+ UAP
+ 10.0.18362.0
+ 10.0.15063.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ false
+ false
+
+
+ x86
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ x86
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ ARM
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ ARM
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ x64
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ false
+ prompt
+
+
+ x64
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ false
+ prompt
+
+
+ PackageReference
+
+
+ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\
+
+
+
+
+
+
+
+
+ 6.2.8
+
+
+
+
+ {f7d32bd0-2749-483e-9a0d-1635ef7e3136}
+ Microsoft.ReactNative
+ False
+
+
+
+
+
+
+
+ 14.0
+
+
+
+
\ No newline at end of file
diff --git a/packages/E2ETest/windows/TreeDumpLibrary/VisualTreeDumper.cs b/packages/E2ETest/windows/TreeDumpLibrary/VisualTreeDumper.cs
new file mode 100644
index 00000000000..7aa02ac0c3a
--- /dev/null
+++ b/packages/E2ETest/windows/TreeDumpLibrary/VisualTreeDumper.cs
@@ -0,0 +1,182 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+
+namespace TreeDumpLibrary
+{
+ public sealed class VisualTreeDumper
+ {
+ class Visitor
+ {
+ private DefaultVisualTreeLogger _logger;
+ private int _indent;
+ private DefaultFilter _filter;
+ private DefaultPropertyValueTranslator _translator;
+ public Visitor(DefaultFilter filter, DefaultPropertyValueTranslator translator, DefaultVisualTreeLogger logger)
+ {
+ _indent = 0;
+ _filter = filter;
+ _translator = translator;
+ _logger = logger;
+ }
+ public void EndVisitNode(DependencyObject obj)
+ {
+ _indent--;
+ _logger.EndNode(_indent, obj.GetType().FullName, obj);
+ }
+
+ public void BeginVisitNode(DependencyObject obj)
+ {
+ _logger.BeginNode(_indent, obj.GetType().FullName, obj);
+ _indent++;
+ }
+
+ public override string ToString()
+ {
+ return _logger.ToString();
+ }
+
+ public bool ShouldVisitPropertiesForNode(DependencyObject node)
+ {
+ return (node as UIElement) != null;
+ }
+
+ public bool ShouldVisitProperty(PropertyInfo propertyInfo)
+ {
+ return _filter.ShouldVisitProperty(propertyInfo.Name);
+ }
+
+ public void VisitProperty(string propertyName, object value)
+ {
+ var v = _translator.PropertyValueToString(propertyName, value);
+ if (_filter.ShouldVisitPropertyValue(v))
+ {
+ _logger.LogProperty(_indent + 1, propertyName, v);
+ }
+ }
+ }
+
+ public static string DumpTree(DependencyObject root, DependencyObject excludedNode)
+ {
+
+ Visitor visitor = new Visitor(new DefaultFilter(),
+ new DefaultPropertyValueTranslator(),
+ new DefaultVisualTreeLogger());
+ WalkThroughTree(root, excludedNode, visitor);
+
+ return visitor.ToString();
+ }
+
+ private static void WalkThroughProperties(DependencyObject node, Visitor visitor)
+ {
+ if (visitor.ShouldVisitPropertiesForNode(node))
+ {
+ var properties = node.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).OrderBy(x => x.Name);
+ foreach (var property in properties)
+ {
+ if (visitor.ShouldVisitProperty(property))
+ {
+ Object value = null;
+
+ try
+ {
+ value = property.GetValue(obj: node, index: null);
+ }
+ catch (Exception e)
+ {
+ value = "Exception when read " + property.Name + e.ToString();
+ }
+ visitor.VisitProperty(property.Name, value);
+ }
+ }
+ }
+ }
+ private static void WalkThroughTree(DependencyObject node, DependencyObject excludedNode, Visitor visitor)
+ {
+ if (node != null)
+ {
+ visitor.BeginVisitNode(node);
+
+ WalkThroughProperties(node, visitor);
+ for (int i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++)
+ {
+ var child = VisualTreeHelper.GetChild(node, i);
+ if (child != excludedNode)
+ {
+ WalkThroughTree(child, excludedNode, visitor);
+ }
+ }
+
+ visitor.EndVisitNode(node);
+ }
+ }
+ }
+ public sealed class DefaultFilter
+ {
+ private List _propertyNameAllowList = new List {"Foreground", "Background", "Padding", "Margin", "RenderSize", "Visibility", "CornerRadius", "BorderThickness",
+ "Width", "Height", "BorderBrush", "VerticalAlignment", "HorizontalAlignment", "Clip", /*"ActualOffset" 19h1*/};
+
+ public bool ShouldVisitPropertyValue(string propertyValue)
+ {
+ return !string.IsNullOrEmpty(propertyValue) && !propertyValue.Equals("NaN") && !propertyValue.StartsWith("Exception");
+ }
+
+ public bool ShouldVisitProperty(string propertyName)
+ {
+ return (_propertyNameAllowList.Contains(propertyName));
+ }
+ }
+ public sealed class DefaultPropertyValueTranslator
+ {
+ public string PropertyValueToString(string propertyName, object propertyObject)
+ {
+ if (propertyObject == null)
+ {
+ return "[NULL]";
+ }
+
+ var brush = propertyObject as SolidColorBrush;
+ if (brush != null)
+ {
+ return brush.Color.ToString();
+ }
+ return propertyObject.ToString();
+ }
+ }
+ public sealed class DefaultVisualTreeLogger
+ {
+ public void BeginNode(int indent, string nodeName, DependencyObject obj)
+ {
+ AppendLogger(indent, string.Format("[{0}]", nodeName));
+ }
+
+ public void EndNode(int indent, string nodeName, DependencyObject obj)
+ {
+ }
+
+ public void LogProperty(int indent, string propertyName, object propertyValue)
+ {
+ AppendLogger(indent, string.Format("{0}={1}", propertyName, propertyValue));
+ }
+
+ public override string ToString()
+ {
+ return _logger.ToString();
+ }
+
+ private StringBuilder _logger = new StringBuilder();
+ private void AppendLogger(int indent, string s)
+ {
+ _logger.AppendLine(s.PadLeft(2 * indent + s.Length));
+ }
+ }
+}
diff --git a/packages/playground/Samples/image.tsx b/packages/playground/Samples/image.tsx
index aac93924745..96628fb6b42 100644
--- a/packages/playground/Samples/image.tsx
+++ b/packages/playground/Samples/image.tsx
@@ -23,12 +23,14 @@ export default class Bootstrap extends React.Component<
| 'repeat'
| undefined;
useLargeImage: boolean;
+ inlcudeBorder: boolean;
imageUrl: string;
}
> {
state = {
selectedResizeMode: 'center' as 'center',
useLargeImage: false,
+ inlcudeBorder: false,
imageUrl: 'http://facebook.github.io/react-native/img/header_logo.png',
};
@@ -68,10 +70,20 @@ export default class Bootstrap extends React.Component<
/>
Large
+
+ No Border
+ this.setState({inlcudeBorder: value})}
+ />
+ Round Border
+
@@ -102,6 +114,14 @@ const styles = StyleSheet.create({
height: '100%',
width: '100%',
},
+ imageWithBorder: {
+ height: '100%',
+ width: '100%',
+ borderRadius: 10.0,
+ borderWidth: 10,
+ borderColor: 'green',
+ backgroundColor: 'red',
+ },
title: {
fontWeight: 'bold',
margin: 5,
diff --git a/vnext/ReactUWP/Utils/PropertyUtils.h b/vnext/ReactUWP/Utils/PropertyUtils.h
index 430c3f06b63..4fb2eccbf5c 100644
--- a/vnext/ReactUWP/Utils/PropertyUtils.h
+++ b/vnext/ReactUWP/Utils/PropertyUtils.h
@@ -32,6 +32,16 @@ static double DefaultOrOverride(double defaultValue, double x) {
return x != c_UndefinedEdge ? x : defaultValue;
};
+static const std::unordered_map edgeTypeMap = {
+ {"borderLeftWidth", ShadowEdges::Left},
+ {"borderTopWidth", ShadowEdges::Top},
+ {"borderRightWidth", ShadowEdges::Right},
+ {"borderBottomWidth", ShadowEdges::Bottom},
+ {"borderStartWidth", ShadowEdges::Start},
+ {"borderEndWidth", ShadowEdges::End},
+ {"borderWidth", ShadowEdges::AllEdges},
+};
+
inline winrt::Windows::UI::Xaml::Thickness GetThickness(double thicknesses[ShadowEdges::CountEdges], bool isRTL) {
const double defaultWidth = std::max(0, thicknesses[ShadowEdges::AllEdges]);
double startWidth = DefaultOrOverride(thicknesses[ShadowEdges::Left], thicknesses[ShadowEdges::Start]);
@@ -173,29 +183,17 @@ bool TryUpdateBorderProperties(
element.ClearValue(T::BorderBrushProperty());
UpdateControlBorderResourceBrushes(element, nullptr);
}
- } else if (propertyName == "borderLeftWidth") {
- if (propertyValue.isNumber())
- SetBorderThickness(node, element, ShadowEdges::Left, propertyValue.asDouble());
- } else if (propertyName == "borderTopWidth") {
- if (propertyValue.isNumber())
- SetBorderThickness(node, element, ShadowEdges::Top, propertyValue.asDouble());
- } else if (propertyName == "borderRightWidth") {
- if (propertyValue.isNumber())
- SetBorderThickness(node, element, ShadowEdges::Right, propertyValue.asDouble());
- } else if (propertyName == "borderBottomWidth") {
- if (propertyValue.isNumber())
- SetBorderThickness(node, element, ShadowEdges::Bottom, propertyValue.asDouble());
- } else if (propertyName == "borderStartWidth") {
- if (propertyValue.isNumber())
- SetBorderThickness(node, element, ShadowEdges::Start, propertyValue.asDouble());
- } else if (propertyName == "borderEndWidth") {
- if (propertyValue.isNumber())
- SetBorderThickness(node, element, ShadowEdges::End, propertyValue.asDouble());
- } else if (propertyName == "borderWidth") {
- if (propertyValue.isNumber())
- SetBorderThickness(node, element, ShadowEdges::AllEdges, propertyValue.asDouble());
} else {
- isBorderProperty = false;
+ auto iter = edgeTypeMap.find(propertyName);
+ if (iter != edgeTypeMap.end()) {
+ if (propertyValue.isNumber()) {
+ SetBorderThickness(node, element, iter->second, propertyValue.asDouble());
+ } else if (propertyValue.isNull()) {
+ SetBorderThickness(node, element, iter->second, 0);
+ }
+ } else {
+ isBorderProperty = false;
+ }
}
return isBorderProperty;
diff --git a/vnext/ReactUWP/Views/Image/ImageViewManager.cpp b/vnext/ReactUWP/Views/Image/ImageViewManager.cpp
index f909df5e7c2..5e2a9222a5a 100644
--- a/vnext/ReactUWP/Views/Image/ImageViewManager.cpp
+++ b/vnext/ReactUWP/Views/Image/ImageViewManager.cpp
@@ -13,6 +13,7 @@
#include
#include
+#include
#include
#include "ReactImage.h"
@@ -82,8 +83,8 @@ class ImageShadowNode : public ShadowNodeBase {
reactImage](const auto &, const bool &succeeded) {
ImageSource source{reactImage->Source()};
- imageViewManager->EmitImageEvent(reactImage.as(), succeeded ? "topLoad" : "topError", source);
- imageViewManager->EmitImageEvent(reactImage.as(), "topLoadEnd", source);
+ imageViewManager->EmitImageEvent(reactImage.as(), succeeded ? "topLoad" : "topError", source);
+ imageViewManager->EmitImageEvent(reactImage.as(), "topLoadEnd", source);
});
}
@@ -103,7 +104,7 @@ const char *ImageViewManager::GetName() const {
}
XamlView ImageViewManager::CreateViewCore(int64_t tag) {
- return ReactImage::Create().as();
+ return ReactImage::Create().as();
}
facebook::react::ShadowNode *ImageViewManager::createShadow() const {
@@ -111,35 +112,43 @@ facebook::react::ShadowNode *ImageViewManager::createShadow() const {
}
void ImageViewManager::UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap) {
- auto canvas{nodeToUpdate->GetView().as()};
+ auto grid{nodeToUpdate->GetView().as()};
- if (canvas == nullptr)
+ if (grid == nullptr)
return;
+ 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(canvas, propertyValue);
+ setSource(grid, propertyValue);
} else if (propertyName == "resizeMode") {
auto resizeMode{json_type_traits::parseJson(propertyValue)};
- auto reactImage{canvas.as()};
+ 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;
}
-
// TODO: overflow
}
Super::UpdateProperties(nodeToUpdate, reactDiffMap);
+
+ if (finalizeBorderRadius)
+ UpdateCornerRadiusOnElement(nodeToUpdate, grid);
}
-void ImageViewManager::EmitImageEvent(winrt::Canvas canvas, const char *eventName, ImageSource &source) {
+void ImageViewManager::EmitImageEvent(winrt::Grid grid, const char *eventName, ImageSource &source) {
auto reactInstance{m_wkReactInstance.lock()};
if (reactInstance == nullptr)
return;
- int64_t tag = canvas.Tag().as().GetInt64();
+ int64_t tag = grid.Tag().as().GetInt64();
folly::dynamic imageSource =
folly::dynamic::object()("url", source.uri)("width", source.width)("height", source.height);
@@ -147,7 +156,7 @@ void ImageViewManager::EmitImageEvent(winrt::Canvas canvas, const char *eventNam
reactInstance->DispatchEvent(tag, eventName, std::move(eventData));
}
-void ImageViewManager::setSource(winrt::Canvas canvas, const folly::dynamic &data) {
+void ImageViewManager::setSource(winrt::Grid grid, const folly::dynamic &data) {
auto instance{m_wkReactInstance.lock()};
if (instance == nullptr)
return;
@@ -155,9 +164,9 @@ void ImageViewManager::setSource(winrt::Canvas canvas, const folly::dynamic &dat
auto sources{json_type_traits>::parseJson(data)};
sources[0].bundleRootPath = instance->GetBundleRootPath();
- auto reactImage{canvas.as()};
+ auto reactImage{grid.as()};
- EmitImageEvent(canvas, "topLoadStart", sources[0]);
+ EmitImageEvent(grid, "topLoadStart", sources[0]);
reactImage->Source(sources[0]);
}
diff --git a/vnext/ReactUWP/Views/Image/ImageViewManager.h b/vnext/ReactUWP/Views/Image/ImageViewManager.h
index 83e9aad2c4c..c22697ab611 100644
--- a/vnext/ReactUWP/Views/Image/ImageViewManager.h
+++ b/vnext/ReactUWP/Views/Image/ImageViewManager.h
@@ -19,13 +19,13 @@ class ImageViewManager : public FrameworkElementViewManager {
folly::dynamic GetExportedCustomDirectEventTypeConstants() const override;
folly::dynamic GetNativeProps() const override;
facebook::react::ShadowNode *createShadow() const override;
- void EmitImageEvent(winrt::Windows::UI::Xaml::Controls::Canvas canvas, const char *eventName, ImageSource &source);
+ void EmitImageEvent(winrt::Windows::UI::Xaml::Controls::Grid grid, const char *eventName, ImageSource &source);
protected:
XamlView CreateViewCore(int64_t tag) override;
private:
- void setSource(winrt::Windows::UI::Xaml::Controls::Canvas canvas, const folly::dynamic &sources);
+ void setSource(winrt::Windows::UI::Xaml::Controls::Grid grid, const folly::dynamic &sources);
};
} // namespace uwp
} // namespace react
diff --git a/vnext/ReactUWP/Views/Image/ReactImage.h b/vnext/ReactUWP/Views/Image/ReactImage.h
index 77563ecde16..612920e10c9 100644
--- a/vnext/ReactUWP/Views/Image/ReactImage.h
+++ b/vnext/ReactUWP/Views/Image/ReactImage.h
@@ -27,8 +27,8 @@ struct ImageSource {
bool packagerAsset = false;
};
-struct ReactImage : winrt::Windows::UI::Xaml::Controls::CanvasT {
- using Super = winrt::Windows::UI::Xaml::Controls::CanvasT;
+struct ReactImage : winrt::Windows::UI::Xaml::Controls::GridT {
+ using Super = winrt::Windows::UI::Xaml::Controls::GridT;
ReactImage();