diff --git a/Samples/CustomControls/CppApp/App.xaml b/Samples/CustomControls/CppApp/App.xaml
new file mode 100644
index 000000000..4ddf47626
--- /dev/null
+++ b/Samples/CustomControls/CppApp/App.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppApp/App.xaml.cpp b/Samples/CustomControls/CppApp/App.xaml.cpp
new file mode 100644
index 000000000..869a8fd9e
--- /dev/null
+++ b/Samples/CustomControls/CppApp/App.xaml.cpp
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include "App.xaml.h"
+#include "MainWindow.xaml.h"
+
+namespace winrt
+{
+ using namespace Windows::Foundation;
+ using namespace Microsoft::UI::Xaml;
+}
+
+namespace winrt::CppApp::implementation
+{
+ App::App()
+ {
+ InitializeComponent();
+
+#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
+ UnhandledException([](winrt::IInspectable const&, winrt::UnhandledExceptionEventArgs const& e)
+ {
+ if (IsDebuggerPresent())
+ {
+ auto errorMessage = e.Message();
+ __debugbreak();
+ }
+ });
+#endif
+ }
+
+ void App::OnLaunched(winrt::LaunchActivatedEventArgs const&)
+ {
+ window = winrt::make();
+ window.Activate();
+ }
+}
diff --git a/Samples/CustomControls/CppApp/App.xaml.h b/Samples/CustomControls/CppApp/App.xaml.h
new file mode 100644
index 000000000..31b689b93
--- /dev/null
+++ b/Samples/CustomControls/CppApp/App.xaml.h
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "App.xaml.g.h"
+#include "pch.h"
+
+namespace winrt::CppApp::implementation
+{
+ struct App : AppT
+ {
+ App();
+
+ void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&);
+
+ private:
+ Microsoft::UI::Xaml::Window window{ nullptr };
+ };
+}
diff --git a/Samples/CustomControls/CppApp/Assets/SplashScreen.png b/Samples/CustomControls/CppApp/Assets/SplashScreen.png
new file mode 100644
index 000000000..184821318
Binary files /dev/null and b/Samples/CustomControls/CppApp/Assets/SplashScreen.png differ
diff --git a/Samples/CustomControls/CppApp/Assets/Square150x150Logo.png b/Samples/CustomControls/CppApp/Assets/Square150x150Logo.png
new file mode 100644
index 000000000..a50c70379
Binary files /dev/null and b/Samples/CustomControls/CppApp/Assets/Square150x150Logo.png differ
diff --git a/Samples/CustomControls/CppApp/Assets/Square44x44Logo.png b/Samples/CustomControls/CppApp/Assets/Square44x44Logo.png
new file mode 100644
index 000000000..844b60c20
Binary files /dev/null and b/Samples/CustomControls/CppApp/Assets/Square44x44Logo.png differ
diff --git a/Samples/CustomControls/CppApp/Assets/Wide310x150Logo.png b/Samples/CustomControls/CppApp/Assets/Wide310x150Logo.png
new file mode 100644
index 000000000..b5d5f2c42
Binary files /dev/null and b/Samples/CustomControls/CppApp/Assets/Wide310x150Logo.png differ
diff --git a/Samples/CustomControls/CppApp/Assets/logo.png b/Samples/CustomControls/CppApp/Assets/logo.png
new file mode 100644
index 000000000..fd2293e7b
Binary files /dev/null and b/Samples/CustomControls/CppApp/Assets/logo.png differ
diff --git a/Samples/CustomControls/CppApp/Assets/windows-sdk.ico b/Samples/CustomControls/CppApp/Assets/windows-sdk.ico
new file mode 100644
index 000000000..3ad20c7c2
Binary files /dev/null and b/Samples/CustomControls/CppApp/Assets/windows-sdk.ico differ
diff --git a/Samples/CustomControls/CppApp/CppApp.vcxproj b/Samples/CustomControls/CppApp/CppApp.vcxproj
new file mode 100644
index 000000000..55f473f09
--- /dev/null
+++ b/Samples/CustomControls/CppApp/CppApp.vcxproj
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+ true
+ true
+ true
+ {34a4ad19-a703-47f3-b279-e505c6a2a935}
+ CppApp
+ CppApp
+
+ $(RootNamespace)
+ en-US
+ 16.0
+ false
+ true
+ Windows Store
+ 10.0
+ 10.0
+ 10.0.17763.0
+ true
+ true
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Debug
+ arm64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+ Release
+ arm64
+
+
+
+ Application
+ Unicode
+ true
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ true
+
+
+
+
+
+
+
+ MainPage.xaml
+ Code
+
+
+
+ App.xaml
+
+
+ MainWindow.xaml
+
+
+
+ Scenario1_CustomControl.xaml
+ Code
+
+
+ Scenario2_UserControl.xaml
+ Code
+
+
+ SettingsPage.xaml
+ Code
+
+
+
+
+
+ Designer
+
+
+
+ Designer
+
+
+ Designer
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+ MainPage.xaml
+ Code
+
+
+ Create
+
+
+ App.xaml
+
+
+ MainWindow.xaml
+
+
+
+
+ Scenario1_CustomControl.xaml
+ Code
+
+
+ Scenario2_UserControl.xaml
+ Code
+
+
+ SettingsPage.xaml
+ Code
+
+
+
+
+ Code
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {bcc816dc-0f01-4f0f-8506-df6afefaea92}
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CppApp/CppApp.vcxproj.filters b/Samples/CustomControls/CppApp/CppApp.vcxproj.filters
new file mode 100644
index 000000000..c37af41cd
--- /dev/null
+++ b/Samples/CustomControls/CppApp/CppApp.vcxproj.filters
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+ {$guid1}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CppApp/MainPage.xaml b/Samples/CustomControls/CppApp/MainPage.xaml
new file mode 100644
index 000000000..3c50ce2e0
--- /dev/null
+++ b/Samples/CustomControls/CppApp/MainPage.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppApp/MainPage.xaml.cpp b/Samples/CustomControls/CppApp/MainPage.xaml.cpp
new file mode 100644
index 000000000..5831c8651
--- /dev/null
+++ b/Samples/CustomControls/CppApp/MainPage.xaml.cpp
@@ -0,0 +1,156 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "MainPage.xaml.h"
+#if __has_include("MainPage.g.cpp")
+#include "MainPage.g.cpp"
+#endif
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+ using namespace Microsoft::UI::Xaml::Controls;
+ using namespace Microsoft::UI::Xaml::Media;
+ using namespace Microsoft::UI::Xaml::Media::Animation;
+ using namespace Microsoft::UI::Xaml::Navigation;
+ using namespace Windows::UI::Xaml::Interop;
+}
+
+namespace winrt::CppApp::implementation
+{
+ CppApp::MainPage MainPage::current{ nullptr };
+
+ MainPage::MainPage()
+ {
+ InitializeComponent();
+ MainPage::current = *this;
+ }
+
+ void MainPage::NotifyUser(hstring const& strMessage, InfoBarSeverity const& severity)
+ {
+ // If called from the UI thread, then update immediately.
+ // Otherwise, schedule a task on the UI thread to perform the update.
+ if (this->DispatcherQueue().HasThreadAccess())
+ {
+ UpdateStatus(strMessage, severity);
+ }
+ else
+ {
+ DispatcherQueue().TryEnqueue([strongThis = get_strong(), this, strMessage, severity]
+ { UpdateStatus(strMessage, severity); });
+ }
+ }
+
+ void MainPage::UpdateStatus(hstring const& strMessage, InfoBarSeverity severity)
+ {
+ infoBar().Message(strMessage);
+ infoBar().IsOpen(!strMessage.empty());
+ infoBar().Severity(severity);
+ }
+
+ void MainPage::NavView_Loaded(IInspectable const&, RoutedEventArgs const&)
+ {
+ for (auto&& s : Scenarios())
+ {
+ FontIcon fontIcon{};
+ fontIcon.FontFamily(winrt::FontFamily(L"Segoe MDL2 Assets"));
+ fontIcon.Glyph(L"\uE82D");
+
+ NavigationViewItem navViewItem{};
+ navViewItem.Content(box_value(s.Title));
+ navViewItem.Tag(box_value(s.ClassName));
+ navViewItem.Icon(fontIcon);
+ NavView().MenuItems().Append(navViewItem);
+ }
+
+ // NavView doesn't load any page by default, so load home page.
+ NavView().SelectedItem(NavView().MenuItems().GetAt(0));
+
+ // If navigation occurs on SelectionChanged, this isn't needed.
+ // Because we use ItemInvoked to navigate, we need to call Navigate
+ // here to load the home page.
+ if (Scenarios().Size() > 0)
+ {
+ NavView_Navigate(Scenarios().GetAt(0).ClassName, nullptr);
+ }
+ }
+
+
+ void MainPage::NavView_ItemInvoked(NavigationView const&, NavigationViewItemInvokedEventArgs const& args)
+ {
+ if (args.IsSettingsInvoked() == true)
+ {
+ hstring xamltypename = winrt::xaml_typename().Name;
+ NavView_Navigate(xamltypename, args.RecommendedNavigationTransitionInfo());
+ }
+ else if (args.InvokedItemContainer() != nullptr)
+ {
+ auto navItemTag = winrt::unbox_value(args.InvokedItemContainer().Tag());
+ if (navItemTag != L"")
+ {
+ NavView_Navigate(navItemTag, args.RecommendedNavigationTransitionInfo());
+ }
+ }
+ }
+
+ void MainPage::NavView_Navigate(hstring navItemTag, NavigationTransitionInfo const&)
+ {
+ TypeName pageType;
+
+ if (navItemTag == winrt::xaml_typename().Name)
+ {
+ pageType = winrt::xaml_typename();
+ }
+ else
+ {
+ pageType.Name = navItemTag;
+ pageType.Kind = TypeKind::Metadata;
+ }
+
+ // Get the page type before navigation so you can prevent duplicate
+ // entries in the backstack.
+ TypeName prePageType = ContentFrame().CurrentSourcePageType();
+
+ // Only navigate if the selected page isn't currently loaded.
+ if (prePageType.Name != pageType.Name)
+ {
+ DrillInNavigationTransitionInfo drillIn;
+ ContentFrame().Navigate(pageType, nullptr, drillIn);
+ }
+ }
+
+ void MainPage::NavView_BackRequested(NavigationView const&, NavigationViewBackRequestedEventArgs const&)
+ {
+ if (ContentFrame().CanGoBack())
+ {
+ ContentFrame().GoBack();
+ }
+ }
+
+ void MainPage::ContentFrame_Navigated(IInspectable const&, NavigationEventArgs const& e)
+ {
+ NavView().IsBackEnabled(ContentFrame().CanGoBack());
+
+ if (ContentFrame().SourcePageType().Name == winrt::xaml_typename().Name)
+ {
+ // SettingsItem is not part of NavView.MenuItems, and doesn't have a Tag.
+ NavView().SelectedItem((NavView().SettingsItem().as()));
+ NavView().Header(winrt::box_value(L"Settings"));
+ }
+ else
+ {
+ for (auto&& item : NavView().MenuItems())
+ {
+ auto navViewItem = item.try_as();
+ if (navViewItem != nullptr &&
+ winrt::unbox_value(navViewItem.Tag()) == e.SourcePageType().Name)
+ {
+ NavView().SelectedItem(navViewItem);
+ NavView().Header(navViewItem.Content());
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Samples/CustomControls/CppApp/MainPage.xaml.h b/Samples/CustomControls/CppApp/MainPage.xaml.h
new file mode 100644
index 000000000..1ae128920
--- /dev/null
+++ b/Samples/CustomControls/CppApp/MainPage.xaml.h
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "MainPage.g.h"
+
+namespace winrt::CppApp::implementation
+{
+ struct MainPage : MainPageT
+ {
+ MainPage();
+ static CppApp::MainPage Current() { return current; }
+ static Windows::Foundation::Collections::IVector Scenarios() { return scenariosInner; }
+ void NotifyUser(hstring const& strMessage, Microsoft::UI::Xaml::Controls::InfoBarSeverity const& severity);
+ void UpdateStatus(hstring const& strMessage, Microsoft::UI::Xaml::Controls::InfoBarSeverity severity);
+ void NavView_Loaded(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e);
+ void NavView_ItemInvoked(Microsoft::UI::Xaml::Controls::NavigationView const& sender, Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs const& args);
+ void NavView_Navigate(hstring navItemTag, Microsoft::UI::Xaml::Media::Animation::NavigationTransitionInfo const& transitionInfo);
+ void NavView_BackRequested(Microsoft::UI::Xaml::Controls::NavigationView const& sender, Microsoft::UI::Xaml::Controls::NavigationViewBackRequestedEventArgs const& args);
+ void ContentFrame_Navigated(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e);
+
+ private:
+ static Windows::Foundation::Collections::IVector scenariosInner;
+ static CppApp::MainPage current;
+ };
+}
+
+namespace winrt::CppApp::factory_implementation
+{
+ struct MainPage : MainPageT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppApp/MainWindow.xaml b/Samples/CustomControls/CppApp/MainWindow.xaml
new file mode 100644
index 000000000..a1f056aea
--- /dev/null
+++ b/Samples/CustomControls/CppApp/MainWindow.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/Samples/CustomControls/CppApp/MainWindow.xaml.cpp b/Samples/CustomControls/CppApp/MainWindow.xaml.cpp
new file mode 100644
index 000000000..4b6d72bf9
--- /dev/null
+++ b/Samples/CustomControls/CppApp/MainWindow.xaml.cpp
@@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "MainWindow.xaml.h"
+#if __has_include("MainWindow.g.cpp")
+#include "MainWindow.g.cpp"
+
+#include "microsoft.ui.xaml.window.h"
+#include "SampleConfiguration.h"
+#endif
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+}
+
+namespace winrt::CppApp::implementation
+{
+ MainWindow::MainWindow()
+ {
+ InitializeComponent();
+
+ Title(winrt::CppApp::SampleConfig::FeatureName);
+
+ HWND hwnd = GetWindowHandle();
+ LoadIcon(hwnd, L"Assets/windows-sdk.ico");
+ SetWindowSize(hwnd, 1050, 800);
+ PlacementCenterWindowInMonitorWin32(hwnd);
+ }
+
+ HWND MainWindow::GetWindowHandle()
+ {
+ if (_hwnd == nullptr)
+ {
+ Window window = *this;
+ window.as()->get_WindowHandle(&_hwnd);
+ }
+ return _hwnd;
+ }
+
+ void MainWindow::LoadIcon(HWND hwnd, wchar_t const* iconPath)
+ {
+ HANDLE hSmallIcon = LoadImageW(nullptr, iconPath, IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+ LR_LOADFROMFILE | LR_SHARED);
+ SendMessageW(hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast(hSmallIcon));
+
+ HANDLE hBigIcon = LoadImageW(nullptr, iconPath, IMAGE_ICON,
+ GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
+ LR_LOADFROMFILE | LR_SHARED);
+ SendMessageW(hwnd, WM_SETICON, ICON_BIG, reinterpret_cast(hBigIcon));
+ }
+
+ void MainWindow::SetWindowSize(HWND hwnd, int width, int height)
+ {
+ // Win32 uses pixels and WinUI 3 uses effective pixels, so you should apply the DPI scale factor
+ const UINT dpi = GetDpiForWindow(hwnd);
+ const float scalingFactor = static_cast(dpi) / 96;
+ const int widthScaled = static_cast(width * scalingFactor);
+ const int heightScaled = static_cast(height * scalingFactor);
+
+ SetWindowPos(hwnd, nullptr, 0, 0, widthScaled, heightScaled, SWP_NOMOVE | SWP_NOZORDER);
+ }
+
+ void MainWindow::PlacementCenterWindowInMonitorWin32(HWND hwnd)
+ {
+ RECT windowMontiorRectToAdjust;
+ GetWindowRect(hwnd, &windowMontiorRectToAdjust);
+ ClipOrCenterRectToMonitorWin32(windowMontiorRectToAdjust);
+ SetWindowPos(hwnd, nullptr, windowMontiorRectToAdjust.left,
+ windowMontiorRectToAdjust.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ void MainWindow::ClipOrCenterRectToMonitorWin32(RECT& adjustedWindowRect)
+ {
+ MONITORINFO mi{ sizeof(mi) };
+ GetMonitorInfoW(MonitorFromRect(&adjustedWindowRect, MONITOR_DEFAULTTONEAREST), &mi);
+
+ const auto& rcWork = mi.rcWork;
+ const int w = adjustedWindowRect.right - adjustedWindowRect.left;
+ const int h = adjustedWindowRect.bottom - adjustedWindowRect.top;
+
+ adjustedWindowRect.left = rcWork.left + (rcWork.right - rcWork.left - w) / 2;
+ adjustedWindowRect.top = rcWork.top + (rcWork.bottom - rcWork.top - h) / 2;
+ adjustedWindowRect.right = adjustedWindowRect.left + w;
+ adjustedWindowRect.bottom = adjustedWindowRect.top + h;
+ }
+}
diff --git a/Samples/CustomControls/CppApp/MainWindow.xaml.h b/Samples/CustomControls/CppApp/MainWindow.xaml.h
new file mode 100644
index 000000000..27c0f2b66
--- /dev/null
+++ b/Samples/CustomControls/CppApp/MainWindow.xaml.h
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "MainWindow.g.h"
+#include "pch.h"
+
+namespace winrt::CppApp::implementation
+{
+ struct MainWindow : MainWindowT
+ {
+ MainWindow();
+
+ private:
+ HWND _hwnd{ nullptr };
+ void SetWindowSize(HWND hwnd, const int width, const int height);
+ HWND GetWindowHandle();
+ void LoadIcon(HWND hwnd, wchar_t const* iconName);
+ void ClipOrCenterRectToMonitorWin32(RECT& rc);
+ void PlacementCenterWindowInMonitorWin32(HWND hwnd);
+ };
+}
+
+namespace winrt::CppApp::factory_implementation
+{
+ struct MainWindow : MainWindowT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppApp/Package.appxmanifest b/Samples/CustomControls/CppApp/Package.appxmanifest
new file mode 100644
index 000000000..8b228300d
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Package.appxmanifest
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+ CppApp
+ Microsoft Corporation
+ Assets\logo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WinRT.Host.dll
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppApp/Project.idl b/Samples/CustomControls/CppApp/Project.idl
new file mode 100644
index 000000000..ac4531be7
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Project.idl
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace CppApp
+{
+ /* The following code is scenario/feature-specific IDL.
+ Samples authors should modify these runtime classes as appropriate. */
+
+ [default_interface]
+ runtimeclass Scenario1_CustomControl : Microsoft.UI.Xaml.Controls.Page
+ {
+ Scenario1_CustomControl();
+ }
+
+ [default_interface]
+ runtimeclass Scenario2_UserControl : Microsoft.UI.Xaml.Controls.Page
+ {
+ Scenario2_UserControl();
+ }
+
+ /* The following code is template-specific IDL.
+ These runtime classes are the same across all C++/WinRT WinUI samples. */
+
+ runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
+ {
+ MainPage();
+ static MainPage Current();
+ void NotifyUser(String strMessage, Microsoft.UI.Xaml.Controls.InfoBarSeverity severity);
+ }
+
+ // To use Scenario in a winrt::Windows::Foundation::Collections::IVector, Scenario should be a WinRT type
+ struct Scenario
+ {
+ String Title;
+ String ClassName;
+ };
+
+ [default_interface]
+ runtimeclass MainWindow : Microsoft.UI.Xaml.Window
+ {
+ MainWindow();
+ }
+
+ [default_interface]
+ runtimeclass SettingsPage : Microsoft.UI.Xaml.Controls.Page
+ {
+ SettingsPage();
+ }
+}
diff --git a/Samples/CustomControls/CppApp/SampleConfiguration.cpp b/Samples/CustomControls/CppApp/SampleConfiguration.cpp
new file mode 100644
index 000000000..5923ca31b
--- /dev/null
+++ b/Samples/CustomControls/CppApp/SampleConfiguration.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "pch.h"
+#include "SampleConfiguration.h"
+#include "MainPage.xaml.h"
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+ using namespace Windows::Foundation::Collections;
+}
+
+namespace winrt::CppApp
+{
+ IVector implementation::MainPage::scenariosInner = single_threaded_observable_vector(
+ {
+ Scenario{ L"Custom Control", hstring(name_of())},
+ Scenario{ L"User Control", hstring(name_of())}
+ });
+
+ hstring SampleConfig::FeatureName{ L"CppApp" };
+ ElementTheme SampleConfig::CurrentTheme{ ElementTheme::Default };
+}
diff --git a/Samples/CustomControls/CppApp/SampleConfiguration.h b/Samples/CustomControls/CppApp/SampleConfiguration.h
new file mode 100644
index 000000000..26cb27c95
--- /dev/null
+++ b/Samples/CustomControls/CppApp/SampleConfiguration.h
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "pch.h"
+
+namespace winrt::CppApp
+{
+ struct SampleConfig
+ {
+ public:
+ static hstring FeatureName;
+ static Microsoft::UI::Xaml::ElementTheme CurrentTheme;
+ };
+}
diff --git a/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml b/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml
new file mode 100644
index 000000000..74e05e00c
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+ Reference a Custom WinUI Button type from a C# component.
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml.cpp b/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml.cpp
new file mode 100644
index 000000000..f347b0b31
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "Scenario1_CustomControl.xaml.h"
+#if __has_include("Scenario1_CustomControl.g.cpp")
+#include "Scenario1_CustomControl.g.cpp"
+#endif
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+ using namespace Microsoft::UI::Xaml::Controls;
+ using namespace Windows::Foundation;
+}
+
+namespace winrt::CppApp::implementation
+{
+ MainPage Scenario1_CustomControl::rootPage{ nullptr };
+
+ Scenario1_CustomControl::Scenario1_CustomControl()
+ {
+ InitializeComponent();
+ Scenario1_CustomControl::rootPage = MainPage::Current();
+ }
+}
diff --git a/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml.h b/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml.h
new file mode 100644
index 000000000..f71045304
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Scenario1_CustomControl.xaml.h
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Scenario1_CustomControl.g.h"
+
+namespace winrt::CppApp::implementation
+{
+ struct Scenario1_CustomControl : Scenario1_CustomControlT
+ {
+ Scenario1_CustomControl();
+ //void SuccessMessage_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&);
+ //void ErrorMessage_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&);
+ //void InformationalMessage_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&);
+ //void ClearMessage_Click(winrt::Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::RoutedEventArgs const&);
+ private:
+ static CppApp::MainPage rootPage;
+ };
+}
+
+namespace winrt::CppApp::factory_implementation
+{
+ struct Scenario1_CustomControl : Scenario1_CustomControlT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml b/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml
new file mode 100644
index 000000000..d066b8b61
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reference a Custom User Control from a C# Component.
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml.cpp b/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml.cpp
new file mode 100644
index 000000000..f6437ed72
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml.cpp
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "Scenario2_UserControl.xaml.h"
+#if __has_include("Scenario2_UserControl.g.cpp")
+#include "Scenario2_UserControl.g.cpp"
+#endif
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+}
+
+namespace winrt::CppApp::implementation
+{
+ Scenario2_UserControl::Scenario2_UserControl()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml.h b/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml.h
new file mode 100644
index 000000000..689313632
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Scenario2_UserControl.xaml.h
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Scenario2_UserControl.g.h"
+
+namespace winrt::CppApp::implementation
+{
+ struct Scenario2_UserControl : Scenario2_UserControlT
+ {
+ Scenario2_UserControl();
+ };
+}
+
+namespace winrt::CppApp::factory_implementation
+{
+ struct Scenario2_UserControl : Scenario2_UserControlT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppApp/SettingsPage.xaml b/Samples/CustomControls/CppApp/SettingsPage.xaml
new file mode 100644
index 000000000..5a4e12dc0
--- /dev/null
+++ b/Samples/CustomControls/CppApp/SettingsPage.xaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+ Light
+
+
+
+
+ Dark
+
+
+
+
+ Default
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppApp/SettingsPage.xaml.cpp b/Samples/CustomControls/CppApp/SettingsPage.xaml.cpp
new file mode 100644
index 000000000..b889cc401
--- /dev/null
+++ b/Samples/CustomControls/CppApp/SettingsPage.xaml.cpp
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "SettingsPage.xaml.h"
+#if __has_include("SettingsPage.g.cpp")
+#include "SettingsPage.g.cpp"
+#endif
+#include
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+ using namespace Microsoft::UI::Xaml::Controls;
+ using namespace Microsoft::UI::Xaml::Navigation;
+ using namespace Windows::Foundation;
+}
+
+namespace winrt::CppApp::implementation
+{
+ SettingsPage::SettingsPage()
+ {
+ InitializeComponent();
+ }
+
+ void SettingsPage::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ for (UIElement&& c : themePanel().Children())
+ {
+ auto tag = c.as().Tag().as();
+ if (tag == SampleConfig::CurrentTheme)
+ {
+ auto radioButton = c.as();
+ radioButton.IsChecked(true);
+ }
+ }
+ }
+
+ void SettingsPage::OnThemeRadioButtonChecked(IInspectable const& sender, RoutedEventArgs const&)
+ {
+ auto radiobutton = sender.as();
+ auto selectedTheme = unbox_value(radiobutton.Tag());
+
+ auto content = MainPage::Current().Content().as();
+ if (content != nullptr)
+ {
+ content.RequestedTheme(selectedTheme);
+ SampleConfig::CurrentTheme = content.RequestedTheme();
+ }
+ }
+}
diff --git a/Samples/CustomControls/CppApp/SettingsPage.xaml.h b/Samples/CustomControls/CppApp/SettingsPage.xaml.h
new file mode 100644
index 000000000..0fd19146c
--- /dev/null
+++ b/Samples/CustomControls/CppApp/SettingsPage.xaml.h
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "SettingsPage.g.h"
+
+namespace winrt::CppApp::implementation
+{
+ struct SettingsPage : SettingsPageT
+ {
+ SettingsPage();
+ void OnNavigatedTo(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e);
+ void OnThemeRadioButtonChecked(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
+ };
+}
+
+namespace winrt::CppApp::factory_implementation
+{
+ struct SettingsPage : SettingsPageT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppApp/Styles.xaml b/Samples/CustomControls/CppApp/Styles.xaml
new file mode 100644
index 000000000..748aef03d
--- /dev/null
+++ b/Samples/CustomControls/CppApp/Styles.xaml
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppApp/app.manifest b/Samples/CustomControls/CppApp/app.manifest
new file mode 100644
index 000000000..6f36cae81
--- /dev/null
+++ b/Samples/CustomControls/CppApp/app.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/Samples/CustomControls/CppApp/packages.config b/Samples/CustomControls/CppApp/packages.config
new file mode 100644
index 000000000..bc372d9a9
--- /dev/null
+++ b/Samples/CustomControls/CppApp/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CppApp/pch.cpp b/Samples/CustomControls/CppApp/pch.cpp
new file mode 100644
index 000000000..40e691ba7
--- /dev/null
+++ b/Samples/CustomControls/CppApp/pch.cpp
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
diff --git a/Samples/CustomControls/CppApp/pch.h b/Samples/CustomControls/CppApp/pch.h
new file mode 100644
index 000000000..697356a9f
--- /dev/null
+++ b/Samples/CustomControls/CppApp/pch.h
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include
+#include
+#include
+#include
+
+// Undefine GetCurrentTime macro to prevent
+// conflict with Storyboard::GetCurrentTime
+#undef GetCurrentTime
+
+#include
+#include
+#include
+#include //For using xaml_typename
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
diff --git a/Samples/CustomControls/CppAppUnpackaged/App.xaml b/Samples/CustomControls/CppAppUnpackaged/App.xaml
new file mode 100644
index 000000000..62ea30142
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/App.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppAppUnpackaged/App.xaml.cpp b/Samples/CustomControls/CppAppUnpackaged/App.xaml.cpp
new file mode 100644
index 000000000..37cff0524
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/App.xaml.cpp
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+
+#include "App.xaml.h"
+#include "MainWindow.xaml.h"
+
+namespace winrt
+{
+ using namespace Windows::Foundation;
+ using namespace Microsoft::UI::Xaml;
+}
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ App::App()
+ {
+ InitializeComponent();
+
+#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
+ UnhandledException([](winrt::IInspectable const&, winrt::UnhandledExceptionEventArgs const& e)
+ {
+ if (IsDebuggerPresent())
+ {
+ auto errorMessage = e.Message();
+ __debugbreak();
+ }
+ });
+#endif
+ }
+
+ void App::OnLaunched(winrt::LaunchActivatedEventArgs const&)
+ {
+ window = winrt::make();
+ window.Activate();
+ }
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/App.xaml.h b/Samples/CustomControls/CppAppUnpackaged/App.xaml.h
new file mode 100644
index 000000000..804665645
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/App.xaml.h
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "App.xaml.g.h"
+#include "pch.h"
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ struct App : AppT
+ {
+ App();
+
+ void OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&);
+
+ private:
+ Microsoft::UI::Xaml::Window window{ nullptr };
+ };
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/Assets/SplashScreen.png b/Samples/CustomControls/CppAppUnpackaged/Assets/SplashScreen.png
new file mode 100644
index 000000000..184821318
Binary files /dev/null and b/Samples/CustomControls/CppAppUnpackaged/Assets/SplashScreen.png differ
diff --git a/Samples/CustomControls/CppAppUnpackaged/Assets/Square150x150Logo.png b/Samples/CustomControls/CppAppUnpackaged/Assets/Square150x150Logo.png
new file mode 100644
index 000000000..a50c70379
Binary files /dev/null and b/Samples/CustomControls/CppAppUnpackaged/Assets/Square150x150Logo.png differ
diff --git a/Samples/CustomControls/CppAppUnpackaged/Assets/Square44x44Logo.png b/Samples/CustomControls/CppAppUnpackaged/Assets/Square44x44Logo.png
new file mode 100644
index 000000000..844b60c20
Binary files /dev/null and b/Samples/CustomControls/CppAppUnpackaged/Assets/Square44x44Logo.png differ
diff --git a/Samples/CustomControls/CppAppUnpackaged/Assets/Wide310x150Logo.png b/Samples/CustomControls/CppAppUnpackaged/Assets/Wide310x150Logo.png
new file mode 100644
index 000000000..b5d5f2c42
Binary files /dev/null and b/Samples/CustomControls/CppAppUnpackaged/Assets/Wide310x150Logo.png differ
diff --git a/Samples/CustomControls/CppAppUnpackaged/Assets/logo.png b/Samples/CustomControls/CppAppUnpackaged/Assets/logo.png
new file mode 100644
index 000000000..fd2293e7b
Binary files /dev/null and b/Samples/CustomControls/CppAppUnpackaged/Assets/logo.png differ
diff --git a/Samples/CustomControls/CppAppUnpackaged/Assets/windows-sdk.ico b/Samples/CustomControls/CppAppUnpackaged/Assets/windows-sdk.ico
new file mode 100644
index 000000000..3ad20c7c2
Binary files /dev/null and b/Samples/CustomControls/CppAppUnpackaged/Assets/windows-sdk.ico differ
diff --git a/Samples/CustomControls/CppAppUnpackaged/CppAppUnpackaged.vcxproj b/Samples/CustomControls/CppAppUnpackaged/CppAppUnpackaged.vcxproj
new file mode 100644
index 000000000..447bf23e8
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/CppAppUnpackaged.vcxproj
@@ -0,0 +1,224 @@
+
+
+
+
+
+
+
+ true
+ true
+ true
+ {b71d15ef-f17b-4e8f-b023-08c4e3b32dab}
+ CppAppUnpackaged
+ CppAppUnpackaged
+
+ $(RootNamespace)
+ en-US
+ 16.0
+ false
+ false
+ Windows Store
+ 10.0
+ 10.0
+ 10.0.17763.0
+ true
+ true
+ None
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Debug
+ arm64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+ Release
+ arm64
+
+
+
+ Application
+ v143
+ Unicode
+ true
+
+
+ true
+ true
+
+
+ false
+ true
+ false
+
+
+
+
+
+
+
+
+
+ Use
+ pch.h
+ $(IntDir)pch.pch
+ Level4
+ %(AdditionalOptions) /bigobj
+
+
+
+
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+
+
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ true
+
+
+
+
+
+
+
+ MainPage.xaml
+ Code
+
+
+
+ App.xaml
+
+
+ MainWindow.xaml
+
+
+
+ Scenario1_CustomControl.xaml
+ Code
+
+
+ Scenario2_UserControl.xaml
+ Code
+
+
+ SettingsPage.xaml
+ Code
+
+
+
+
+
+ Designer
+
+
+
+ Designer
+
+
+ Designer
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+ MainPage.xaml
+ Code
+
+
+ Create
+
+
+ App.xaml
+
+
+ MainWindow.xaml
+
+
+
+
+ Scenario1_CustomControl.xaml
+ Code
+
+
+ Scenario2_UserControl.xaml
+ Code
+
+
+ SettingsPage.xaml
+ Code
+
+
+
+
+ Code
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {bcc816dc-0f01-4f0f-8506-df6afefaea92}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CppAppUnpackaged/CppAppUnpackaged.vcxproj.filters b/Samples/CustomControls/CppAppUnpackaged/CppAppUnpackaged.vcxproj.filters
new file mode 100644
index 000000000..213754c34
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/CppAppUnpackaged.vcxproj.filters
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
+
+ {$guid1}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml b/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml
new file mode 100644
index 000000000..162fae80c
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml.cpp b/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml.cpp
new file mode 100644
index 000000000..e32fc129a
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml.cpp
@@ -0,0 +1,156 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "MainPage.xaml.h"
+#if __has_include("MainPage.g.cpp")
+#include "MainPage.g.cpp"
+#endif
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+ using namespace Microsoft::UI::Xaml::Controls;
+ using namespace Microsoft::UI::Xaml::Media;
+ using namespace Microsoft::UI::Xaml::Media::Animation;
+ using namespace Microsoft::UI::Xaml::Navigation;
+ using namespace Windows::UI::Xaml::Interop;
+}
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ CppAppUnpackaged::MainPage MainPage::current{ nullptr };
+
+ MainPage::MainPage()
+ {
+ InitializeComponent();
+ MainPage::current = *this;
+ }
+
+ void MainPage::NotifyUser(hstring const& strMessage, InfoBarSeverity const& severity)
+ {
+ // If called from the UI thread, then update immediately.
+ // Otherwise, schedule a task on the UI thread to perform the update.
+ if (this->DispatcherQueue().HasThreadAccess())
+ {
+ UpdateStatus(strMessage, severity);
+ }
+ else
+ {
+ DispatcherQueue().TryEnqueue([strongThis = get_strong(), this, strMessage, severity]
+ { UpdateStatus(strMessage, severity); });
+ }
+ }
+
+ void MainPage::UpdateStatus(hstring const& strMessage, InfoBarSeverity severity)
+ {
+ infoBar().Message(strMessage);
+ infoBar().IsOpen(!strMessage.empty());
+ infoBar().Severity(severity);
+ }
+
+ void MainPage::NavView_Loaded(IInspectable const&, RoutedEventArgs const&)
+ {
+ for (auto&& s : Scenarios())
+ {
+ FontIcon fontIcon{};
+ fontIcon.FontFamily(winrt::FontFamily(L"Segoe MDL2 Assets"));
+ fontIcon.Glyph(L"\uE82D");
+
+ NavigationViewItem navViewItem{};
+ navViewItem.Content(box_value(s.Title));
+ navViewItem.Tag(box_value(s.ClassName));
+ navViewItem.Icon(fontIcon);
+ NavView().MenuItems().Append(navViewItem);
+ }
+
+ // NavView doesn't load any page by default, so load home page.
+ NavView().SelectedItem(NavView().MenuItems().GetAt(0));
+
+ // If navigation occurs on SelectionChanged, this isn't needed.
+ // Because we use ItemInvoked to navigate, we need to call Navigate
+ // here to load the home page.
+ if (Scenarios().Size() > 0)
+ {
+ NavView_Navigate(Scenarios().GetAt(0).ClassName, nullptr);
+ }
+ }
+
+
+ void MainPage::NavView_ItemInvoked(NavigationView const&, NavigationViewItemInvokedEventArgs const& args)
+ {
+ if (args.IsSettingsInvoked() == true)
+ {
+ hstring xamltypename = winrt::xaml_typename().Name;
+ NavView_Navigate(xamltypename, args.RecommendedNavigationTransitionInfo());
+ }
+ else if (args.InvokedItemContainer() != nullptr)
+ {
+ auto navItemTag = winrt::unbox_value(args.InvokedItemContainer().Tag());
+ if (navItemTag != L"")
+ {
+ NavView_Navigate(navItemTag, args.RecommendedNavigationTransitionInfo());
+ }
+ }
+ }
+
+ void MainPage::NavView_Navigate(hstring navItemTag, NavigationTransitionInfo const&)
+ {
+ TypeName pageType;
+
+ if (navItemTag == winrt::xaml_typename().Name)
+ {
+ pageType = winrt::xaml_typename();
+ }
+ else
+ {
+ pageType.Name = navItemTag;
+ pageType.Kind = TypeKind::Metadata;
+ }
+
+ // Get the page type before navigation so you can prevent duplicate
+ // entries in the backstack.
+ TypeName prePageType = ContentFrame().CurrentSourcePageType();
+
+ // Only navigate if the selected page isn't currently loaded.
+ if (prePageType.Name != pageType.Name)
+ {
+ DrillInNavigationTransitionInfo drillIn;
+ ContentFrame().Navigate(pageType, nullptr, drillIn);
+ }
+ }
+
+ void MainPage::NavView_BackRequested(NavigationView const&, NavigationViewBackRequestedEventArgs const&)
+ {
+ if (ContentFrame().CanGoBack())
+ {
+ ContentFrame().GoBack();
+ }
+ }
+
+ void MainPage::ContentFrame_Navigated(IInspectable const&, NavigationEventArgs const& e)
+ {
+ NavView().IsBackEnabled(ContentFrame().CanGoBack());
+
+ if (ContentFrame().SourcePageType().Name == winrt::xaml_typename().Name)
+ {
+ // SettingsItem is not part of NavView.MenuItems, and doesn't have a Tag.
+ NavView().SelectedItem((NavView().SettingsItem().as()));
+ NavView().Header(winrt::box_value(L"Settings"));
+ }
+ else
+ {
+ for (auto&& item : NavView().MenuItems())
+ {
+ auto navViewItem = item.try_as();
+ if (navViewItem != nullptr &&
+ winrt::unbox_value(navViewItem.Tag()) == e.SourcePageType().Name)
+ {
+ NavView().SelectedItem(navViewItem);
+ NavView().Header(navViewItem.Content());
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml.h b/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml.h
new file mode 100644
index 000000000..1fcec1038
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/MainPage.xaml.h
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "MainPage.g.h"
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ struct MainPage : MainPageT
+ {
+ MainPage();
+ static CppAppUnpackaged::MainPage Current() { return current; }
+ static Windows::Foundation::Collections::IVector Scenarios() { return scenariosInner; }
+ void NotifyUser(hstring const& strMessage, Microsoft::UI::Xaml::Controls::InfoBarSeverity const& severity);
+ void UpdateStatus(hstring const& strMessage, Microsoft::UI::Xaml::Controls::InfoBarSeverity severity);
+ void NavView_Loaded(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& e);
+ void NavView_ItemInvoked(Microsoft::UI::Xaml::Controls::NavigationView const& sender, Microsoft::UI::Xaml::Controls::NavigationViewItemInvokedEventArgs const& args);
+ void NavView_Navigate(hstring navItemTag, Microsoft::UI::Xaml::Media::Animation::NavigationTransitionInfo const& transitionInfo);
+ void NavView_BackRequested(Microsoft::UI::Xaml::Controls::NavigationView const& sender, Microsoft::UI::Xaml::Controls::NavigationViewBackRequestedEventArgs const& args);
+ void ContentFrame_Navigated(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e);
+
+ private:
+ static Windows::Foundation::Collections::IVector scenariosInner;
+ static CppAppUnpackaged::MainPage current;
+ };
+}
+
+namespace winrt::CppAppUnpackaged::factory_implementation
+{
+ struct MainPage : MainPageT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml b/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml
new file mode 100644
index 000000000..beaa656a9
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml.cpp b/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml.cpp
new file mode 100644
index 000000000..64dc05ebb
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml.cpp
@@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "MainWindow.xaml.h"
+#if __has_include("MainWindow.g.cpp")
+#include "MainWindow.g.cpp"
+
+#include "microsoft.ui.xaml.window.h"
+#include "SampleConfiguration.h"
+#endif
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+}
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ MainWindow::MainWindow()
+ {
+ InitializeComponent();
+
+ Title(winrt::CppAppUnpackaged::SampleConfig::FeatureName);
+
+ HWND hwnd = GetWindowHandle();
+ LoadIcon(hwnd, L"Assets/windows-sdk.ico");
+ SetWindowSize(hwnd, 1050, 800);
+ PlacementCenterWindowInMonitorWin32(hwnd);
+ }
+
+ HWND MainWindow::GetWindowHandle()
+ {
+ if (_hwnd == nullptr)
+ {
+ Window window = *this;
+ window.as()->get_WindowHandle(&_hwnd);
+ }
+ return _hwnd;
+ }
+
+ void MainWindow::LoadIcon(HWND hwnd, wchar_t const* iconPath)
+ {
+ HANDLE hSmallIcon = LoadImageW(nullptr, iconPath, IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+ LR_LOADFROMFILE | LR_SHARED);
+ SendMessageW(hwnd, WM_SETICON, ICON_SMALL, reinterpret_cast(hSmallIcon));
+
+ HANDLE hBigIcon = LoadImageW(nullptr, iconPath, IMAGE_ICON,
+ GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
+ LR_LOADFROMFILE | LR_SHARED);
+ SendMessageW(hwnd, WM_SETICON, ICON_BIG, reinterpret_cast(hBigIcon));
+ }
+
+ void MainWindow::SetWindowSize(HWND hwnd, int width, int height)
+ {
+ // Win32 uses pixels and WinUI 3 uses effective pixels, so you should apply the DPI scale factor
+ const UINT dpi = GetDpiForWindow(hwnd);
+ const float scalingFactor = static_cast(dpi) / 96;
+ const int widthScaled = static_cast(width * scalingFactor);
+ const int heightScaled = static_cast(height * scalingFactor);
+
+ SetWindowPos(hwnd, nullptr, 0, 0, widthScaled, heightScaled, SWP_NOMOVE | SWP_NOZORDER);
+ }
+
+ void MainWindow::PlacementCenterWindowInMonitorWin32(HWND hwnd)
+ {
+ RECT windowMontiorRectToAdjust;
+ GetWindowRect(hwnd, &windowMontiorRectToAdjust);
+ ClipOrCenterRectToMonitorWin32(windowMontiorRectToAdjust);
+ SetWindowPos(hwnd, nullptr, windowMontiorRectToAdjust.left,
+ windowMontiorRectToAdjust.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
+ }
+
+ void MainWindow::ClipOrCenterRectToMonitorWin32(RECT& adjustedWindowRect)
+ {
+ MONITORINFO mi{ sizeof(mi) };
+ GetMonitorInfoW(MonitorFromRect(&adjustedWindowRect, MONITOR_DEFAULTTONEAREST), &mi);
+
+ const auto& rcWork = mi.rcWork;
+ const int w = adjustedWindowRect.right - adjustedWindowRect.left;
+ const int h = adjustedWindowRect.bottom - adjustedWindowRect.top;
+
+ adjustedWindowRect.left = rcWork.left + (rcWork.right - rcWork.left - w) / 2;
+ adjustedWindowRect.top = rcWork.top + (rcWork.bottom - rcWork.top - h) / 2;
+ adjustedWindowRect.right = adjustedWindowRect.left + w;
+ adjustedWindowRect.bottom = adjustedWindowRect.top + h;
+ }
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml.h b/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml.h
new file mode 100644
index 000000000..119debdb0
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/MainWindow.xaml.h
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "MainWindow.g.h"
+#include "pch.h"
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ struct MainWindow : MainWindowT
+ {
+ MainWindow();
+
+ private:
+ HWND _hwnd{ nullptr };
+ void SetWindowSize(HWND hwnd, const int width, const int height);
+ HWND GetWindowHandle();
+ void LoadIcon(HWND hwnd, wchar_t const* iconName);
+ void ClipOrCenterRectToMonitorWin32(RECT& rc);
+ void PlacementCenterWindowInMonitorWin32(HWND hwnd);
+ };
+}
+
+namespace winrt::CppAppUnpackaged::factory_implementation
+{
+ struct MainWindow : MainWindowT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/Project.idl b/Samples/CustomControls/CppAppUnpackaged/Project.idl
new file mode 100644
index 000000000..c0b042982
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/Project.idl
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace CppAppUnpackaged
+{
+ /* The following code is scenario/feature-specific IDL.
+ Samples authors should modify these runtime classes as appropriate. */
+
+ [default_interface]
+ runtimeclass Scenario1_CustomControl : Microsoft.UI.Xaml.Controls.Page
+ {
+ Scenario1_CustomControl();
+ }
+
+ [default_interface]
+ runtimeclass Scenario2_UserControl : Microsoft.UI.Xaml.Controls.Page
+ {
+ Scenario2_UserControl();
+ }
+
+ /* The following code is template-specific IDL.
+ These runtime classes are the same across all C++/WinRT WinUI samples. */
+
+ runtimeclass MainPage : Microsoft.UI.Xaml.Controls.Page
+ {
+ MainPage();
+ static MainPage Current();
+ void NotifyUser(String strMessage, Microsoft.UI.Xaml.Controls.InfoBarSeverity severity);
+ }
+
+ // To use Scenario in a winrt::Windows::Foundation::Collections::IVector, Scenario should be a WinRT type
+ struct Scenario
+ {
+ String Title;
+ String ClassName;
+ };
+
+ [default_interface]
+ runtimeclass MainWindow : Microsoft.UI.Xaml.Window
+ {
+ MainWindow();
+ }
+
+ [default_interface]
+ runtimeclass SettingsPage : Microsoft.UI.Xaml.Controls.Page
+ {
+ SettingsPage();
+ }
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/SampleConfiguration.cpp b/Samples/CustomControls/CppAppUnpackaged/SampleConfiguration.cpp
new file mode 100644
index 000000000..a4ddefd1f
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/SampleConfiguration.cpp
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "pch.h"
+#include "SampleConfiguration.h"
+#include "MainPage.xaml.h"
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+ using namespace Windows::Foundation::Collections;
+}
+
+namespace winrt::CppAppUnpackaged
+{
+ IVector implementation::MainPage::scenariosInner = single_threaded_observable_vector(
+ {
+ Scenario{ L"Scenario 1", hstring(name_of())},
+ Scenario{ L"Scenario 2", hstring(name_of())}
+ });
+
+ hstring SampleConfig::FeatureName{ L"CppAppUnpackaged" };
+ ElementTheme SampleConfig::CurrentTheme{ ElementTheme::Default };
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/SampleConfiguration.h b/Samples/CustomControls/CppAppUnpackaged/SampleConfiguration.h
new file mode 100644
index 000000000..f2c662d34
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/SampleConfiguration.h
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include "pch.h"
+
+namespace winrt::CppAppUnpackaged
+{
+ struct SampleConfig
+ {
+ public:
+ static hstring FeatureName;
+ static Microsoft::UI::Xaml::ElementTheme CurrentTheme;
+ };
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml b/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml
new file mode 100644
index 000000000..7c97b10c0
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+ Reference a Custom WinUI Button type from a C# component.
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml.cpp b/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml.cpp
new file mode 100644
index 000000000..b18dd876f
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml.cpp
@@ -0,0 +1,26 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "Scenario1_CustomControl.xaml.h"
+#if __has_include("Scenario1_CustomControl.g.cpp")
+#include "Scenario1_CustomControl.g.cpp"
+#endif
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+ using namespace Microsoft::UI::Xaml::Controls;
+ using namespace Windows::Foundation;
+}
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ MainPage Scenario1_CustomControl::rootPage{ nullptr };
+
+ Scenario1_CustomControl::Scenario1_CustomControl()
+ {
+ InitializeComponent();
+ Scenario1_CustomControl::rootPage = MainPage::Current();
+ }
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml.h b/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml.h
new file mode 100644
index 000000000..b49ced08a
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/Scenario1_CustomControl.xaml.h
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Scenario1_CustomControl.g.h"
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ struct Scenario1_CustomControl : Scenario1_CustomControlT
+ {
+ Scenario1_CustomControl();
+ private:
+ static CppAppUnpackaged::MainPage rootPage;
+ };
+}
+
+namespace winrt::CppAppUnpackaged::factory_implementation
+{
+ struct Scenario1_CustomControl : Scenario1_CustomControlT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml b/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml
new file mode 100644
index 000000000..f167a8988
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reference a Custom User Control from a C# Component.
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml.cpp b/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml.cpp
new file mode 100644
index 000000000..b36d7bd6b
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml.cpp
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "Scenario2_UserControl.xaml.h"
+#if __has_include("Scenario2_UserControl.g.cpp")
+#include "Scenario2_UserControl.g.cpp"
+#endif
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+}
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ Scenario2_UserControl::Scenario2_UserControl()
+ {
+ InitializeComponent();
+ }
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml.h b/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml.h
new file mode 100644
index 000000000..34f644fb8
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/Scenario2_UserControl.xaml.h
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "Scenario2_UserControl.g.h"
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ struct Scenario2_UserControl : Scenario2_UserControlT
+ {
+ Scenario2_UserControl();
+ };
+}
+
+namespace winrt::CppAppUnpackaged::factory_implementation
+{
+ struct Scenario2_UserControl : Scenario2_UserControlT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml b/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml
new file mode 100644
index 000000000..b508656a1
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+ Light
+
+
+
+
+ Dark
+
+
+
+
+ Default
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml.cpp b/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml.cpp
new file mode 100644
index 000000000..2b476a140
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml.cpp
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "SettingsPage.xaml.h"
+#if __has_include("SettingsPage.g.cpp")
+#include "SettingsPage.g.cpp"
+#endif
+#include
+
+namespace winrt
+{
+ using namespace Microsoft::UI::Xaml;
+ using namespace Microsoft::UI::Xaml::Controls;
+ using namespace Microsoft::UI::Xaml::Navigation;
+ using namespace Windows::Foundation;
+}
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ SettingsPage::SettingsPage()
+ {
+ InitializeComponent();
+ }
+
+ void SettingsPage::OnNavigatedTo(NavigationEventArgs const&)
+ {
+ for (UIElement&& c : themePanel().Children())
+ {
+ auto tag = c.as().Tag().as();
+ if (tag == SampleConfig::CurrentTheme)
+ {
+ auto radioButton = c.as();
+ radioButton.IsChecked(true);
+ }
+ }
+ }
+
+ void SettingsPage::OnThemeRadioButtonChecked(IInspectable const& sender, RoutedEventArgs const&)
+ {
+ auto radiobutton = sender.as();
+ auto selectedTheme = unbox_value(radiobutton.Tag());
+
+ auto content = MainPage::Current().Content().as();
+ if (content != nullptr)
+ {
+ content.RequestedTheme(selectedTheme);
+ SampleConfig::CurrentTheme = content.RequestedTheme();
+ }
+ }
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml.h b/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml.h
new file mode 100644
index 000000000..356d79efd
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/SettingsPage.xaml.h
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "SettingsPage.g.h"
+
+namespace winrt::CppAppUnpackaged::implementation
+{
+ struct SettingsPage : SettingsPageT
+ {
+ SettingsPage();
+ void OnNavigatedTo(Microsoft::UI::Xaml::Navigation::NavigationEventArgs const& e);
+ void OnThemeRadioButtonChecked(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
+ };
+}
+
+namespace winrt::CppAppUnpackaged::factory_implementation
+{
+ struct SettingsPage : SettingsPageT
+ {
+ };
+}
diff --git a/Samples/CustomControls/CppAppUnpackaged/Styles.xaml b/Samples/CustomControls/CppAppUnpackaged/Styles.xaml
new file mode 100644
index 000000000..a16ffe768
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/Styles.xaml
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppAppUnpackaged/app.manifest b/Samples/CustomControls/CppAppUnpackaged/app.manifest
new file mode 100644
index 000000000..2691059c1
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/app.manifest
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CppAppUnpackaged/packages.config b/Samples/CustomControls/CppAppUnpackaged/packages.config
new file mode 100644
index 000000000..83878b848
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CppAppUnpackaged/pch.cpp b/Samples/CustomControls/CppAppUnpackaged/pch.cpp
new file mode 100644
index 000000000..40e691ba7
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/pch.cpp
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "pch.h"
diff --git a/Samples/CustomControls/CppAppUnpackaged/pch.h b/Samples/CustomControls/CppAppUnpackaged/pch.h
new file mode 100644
index 000000000..697356a9f
--- /dev/null
+++ b/Samples/CustomControls/CppAppUnpackaged/pch.h
@@ -0,0 +1,33 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+#include
+#include
+#include
+#include
+
+// Undefine GetCurrentTime macro to prevent
+// conflict with Storyboard::GetCurrentTime
+#undef GetCurrentTime
+
+#include
+#include
+#include
+#include //For using xaml_typename
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
diff --git a/Samples/CustomControls/CsApp/App.xaml b/Samples/CustomControls/CsApp/App.xaml
new file mode 100644
index 000000000..cf0977d69
--- /dev/null
+++ b/Samples/CustomControls/CsApp/App.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/App.xaml.cs b/Samples/CustomControls/CsApp/App.xaml.cs
new file mode 100644
index 000000000..178198118
--- /dev/null
+++ b/Samples/CustomControls/CsApp/App.xaml.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.UI.Xaml;
+
+namespace CsApp
+{
+ public partial class App : Application
+ {
+ private Window mainWindow;
+
+ public App()
+ {
+ this.InitializeComponent();
+ }
+
+ protected override void OnLaunched(LaunchActivatedEventArgs args)
+ {
+ mainWindow = new MainWindow();
+ mainWindow.Activate();
+ }
+ }
+}
diff --git a/Samples/CustomControls/CsApp/Assets/SplashScreen.png b/Samples/CustomControls/CsApp/Assets/SplashScreen.png
new file mode 100644
index 000000000..184821318
Binary files /dev/null and b/Samples/CustomControls/CsApp/Assets/SplashScreen.png differ
diff --git a/Samples/CustomControls/CsApp/Assets/Square150x150Logo.png b/Samples/CustomControls/CsApp/Assets/Square150x150Logo.png
new file mode 100644
index 000000000..a50c70379
Binary files /dev/null and b/Samples/CustomControls/CsApp/Assets/Square150x150Logo.png differ
diff --git a/Samples/CustomControls/CsApp/Assets/Square44x44Logo.png b/Samples/CustomControls/CsApp/Assets/Square44x44Logo.png
new file mode 100644
index 000000000..844b60c20
Binary files /dev/null and b/Samples/CustomControls/CsApp/Assets/Square44x44Logo.png differ
diff --git a/Samples/CustomControls/CsApp/Assets/Wide310x150Logo.png b/Samples/CustomControls/CsApp/Assets/Wide310x150Logo.png
new file mode 100644
index 000000000..b5d5f2c42
Binary files /dev/null and b/Samples/CustomControls/CsApp/Assets/Wide310x150Logo.png differ
diff --git a/Samples/CustomControls/CsApp/Assets/logo.png b/Samples/CustomControls/CsApp/Assets/logo.png
new file mode 100644
index 000000000..fd2293e7b
Binary files /dev/null and b/Samples/CustomControls/CsApp/Assets/logo.png differ
diff --git a/Samples/CustomControls/CsApp/Assets/windows-sdk.ico b/Samples/CustomControls/CsApp/Assets/windows-sdk.ico
new file mode 100644
index 000000000..16b6a4021
Binary files /dev/null and b/Samples/CustomControls/CsApp/Assets/windows-sdk.ico differ
diff --git a/Samples/CustomControls/CsApp/CsApp.csproj b/Samples/CustomControls/CsApp/CsApp.csproj
new file mode 100644
index 000000000..6e07d6ee6
--- /dev/null
+++ b/Samples/CustomControls/CsApp/CsApp.csproj
@@ -0,0 +1,44 @@
+
+
+ WinExe
+ net6.0-windows10.0.19041.0
+ 10.0.17763.0
+ CsApp
+ app.manifest
+ x86;x64;arm64
+ win10-x86;win10-x64;win10-arm64
+ true
+ true
+ Properties\PublishProfiles\win10-$(Platform).pubxml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/MainPage.xaml b/Samples/CustomControls/CsApp/MainPage.xaml
new file mode 100644
index 000000000..e241f55e1
--- /dev/null
+++ b/Samples/CustomControls/CsApp/MainPage.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/MainPage.xaml.cs b/Samples/CustomControls/CsApp/MainPage.xaml.cs
new file mode 100644
index 000000000..96466e5e3
--- /dev/null
+++ b/Samples/CustomControls/CsApp/MainPage.xaml.cs
@@ -0,0 +1,150 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Navigation;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace CsApp
+{
+ public partial class MainPage : Page
+ {
+ public static MainPage Current;
+ public List Scenarios => this.scenarios;
+
+ public MainPage()
+ {
+ InitializeComponent();
+
+ // This is a static public property that allows downstream pages to get a handle to the MainPage instance
+ // in order to call methods that are in this class.
+ Current = this;
+ }
+
+ public void NotifyUser(string strMessage, InfoBarSeverity severity, bool isOpen = true)
+ {
+ // If called from the UI thread, then update immediately.
+ // Otherwise, schedule a task on the UI thread to perform the update.
+ if (DispatcherQueue.HasThreadAccess)
+ {
+ UpdateStatus(strMessage, severity, isOpen);
+ }
+ else
+ {
+ DispatcherQueue.TryEnqueue(() =>
+ {
+ UpdateStatus(strMessage, severity, isOpen);
+ });
+ }
+ }
+
+ private void UpdateStatus(string strMessage, InfoBarSeverity severity, bool isOpen)
+ {
+ infoBar.Message = strMessage;
+ infoBar.IsOpen = isOpen;
+ infoBar.Severity = severity;
+ }
+
+ private void NavView_Loaded(object sender, RoutedEventArgs e)
+ {
+ foreach (Scenario item in scenarios)
+ {
+ NavView.MenuItems.Add(new NavigationViewItem
+ {
+ Content = item.Title,
+ Tag = item.ClassName,
+ Icon = new FontIcon() { FontFamily = new("Segoe MDL2 Assets"), Glyph = "\uE82D" }
+ });
+ }
+
+ // NavView doesn't load any page by default, so load home page.
+ NavView.SelectedItem = NavView.MenuItems[0];
+
+ // If navigation occurs on SelectionChanged, this isn't needed.
+ // Because we use ItemInvoked to navigate, we need to call Navigate
+ // here to load the home page.
+ if (scenarios is not null && scenarios.Count > 0)
+ {
+ NavView_Navigate(scenarios.First().ClassName, new Microsoft.UI.Xaml.Media.Animation.EntranceNavigationTransitionInfo());
+ }
+ }
+
+ private void NavView_Navigate(string navItemTag, Microsoft.UI.Xaml.Media.Animation.NavigationTransitionInfo transitionInfo)
+ {
+ Type page;
+
+ if (navItemTag == nameof(SettingsPage))
+ {
+ page = typeof(SettingsPage);
+ }
+ else
+ {
+ Scenario item = scenarios.First(p => p.ClassName.Equals(navItemTag));
+ page = Type.GetType(item.ClassName);
+ }
+
+ // Get the page type before navigation so you can prevent duplicate
+ // entries in the backstack.
+ var preNavPageType = ContentFrame.CurrentSourcePageType;
+
+ // Only navigate if the selected page isn't currently loaded.
+ if ((page is not null) && !Type.Equals(preNavPageType, page))
+ {
+ ContentFrame.Navigate(page, null, transitionInfo);
+ }
+ }
+
+ private void NavView_BackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args)
+ {
+ if (ContentFrame.CanGoBack)
+ {
+ ContentFrame.GoBack();
+ }
+ }
+
+ private void NavView_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
+ {
+ var naViewItemInvoked = (NavigationViewItem)args.InvokedItemContainer;
+
+ if (args.IsSettingsInvoked)
+ {
+ NavView_Navigate(nameof(SettingsPage), args.RecommendedNavigationTransitionInfo);
+ }
+ else if (args.InvokedItemContainer is not null)
+ {
+ var navItemTag = args.InvokedItemContainer.Tag?.ToString();
+ if (!string.IsNullOrEmpty(navItemTag))
+ {
+ NavView_Navigate(navItemTag, new Microsoft.UI.Xaml.Media.Animation.EntranceNavigationTransitionInfo());
+ }
+ }
+ }
+
+ private void ContentFrame_Navigated(object sender, NavigationEventArgs e)
+ {
+ NavView.IsBackEnabled = ContentFrame.CanGoBack;
+
+ if (ContentFrame.SourcePageType == typeof(SettingsPage))
+ {
+ // SettingsItem is not part of NavView.MenuItems, and doesn't have a Tag.
+ NavView.SelectedItem = (NavigationViewItem)NavView.SettingsItem;
+ NavView.Header = "Settings";
+ }
+ else if (ContentFrame.SourcePageType != null)
+ {
+ var item = scenarios.First(p => p.ClassName == e.SourcePageType.FullName);
+ var menuItems = NavView.MenuItems;
+
+ NavView.SelectedItem = NavView.MenuItems
+ .OfType()
+ .First(n => n.Tag.Equals(item.ClassName));
+
+ NavView.Header =
+ ((NavigationViewItem)NavView.SelectedItem)?.Content?.ToString();
+ }
+ }
+ }
+}
diff --git a/Samples/CustomControls/CsApp/MainWindow.xaml b/Samples/CustomControls/CsApp/MainWindow.xaml
new file mode 100644
index 000000000..05fba2604
--- /dev/null
+++ b/Samples/CustomControls/CsApp/MainWindow.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/MainWindow.xaml.cs b/Samples/CustomControls/CsApp/MainWindow.xaml.cs
new file mode 100644
index 000000000..c371fcb0a
--- /dev/null
+++ b/Samples/CustomControls/CsApp/MainWindow.xaml.cs
@@ -0,0 +1,97 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.UI.Xaml;
+using System;
+using System.Runtime.InteropServices;
+using Windows.Win32.Foundation;
+using Windows.Win32.Graphics.Gdi;
+using Windows.Win32.UI.Controls;
+using Windows.Win32.UI.WindowsAndMessaging;
+using static Windows.Win32.Constants;
+using static Windows.Win32.PInvoke;
+
+namespace CsApp
+{
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ this.InitializeComponent();
+
+ Title = SampleConfig.FeatureName;
+
+ HWND hwnd = (HWND)WinRT.Interop.WindowNative.GetWindowHandle(this);
+ LoadIcon(hwnd, "Assets/windows-sdk.ico");
+ SetWindowSize(hwnd, 1050, 800);
+ PlacementCenterWindowInMonitorWin32(hwnd);
+ }
+
+ private unsafe void LoadIcon(HWND hwnd, string iconName)
+ {
+ const int ICON_SMALL = 0;
+ const int ICON_BIG = 1;
+
+ fixed (char* nameLocal = iconName)
+ {
+ HANDLE smallIcon = LoadImage(default,
+ nameLocal,
+ GDI_IMAGE_TYPE.IMAGE_ICON,
+ GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CXSMICON),
+ GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYSMICON),
+ IMAGE_FLAGS.LR_LOADFROMFILE | IMAGE_FLAGS.LR_SHARED);
+ SendMessage(hwnd, WM_SETICON, ICON_SMALL, smallIcon.Value);
+ }
+
+ fixed (char* nameLocal = iconName)
+ {
+ HANDLE bigIcon = LoadImage(default,
+ nameLocal,
+ GDI_IMAGE_TYPE.IMAGE_ICON,
+ GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CXSMICON),
+ GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYSMICON),
+ IMAGE_FLAGS.LR_LOADFROMFILE | IMAGE_FLAGS.LR_SHARED);
+ SendMessage(hwnd, WM_SETICON, ICON_BIG, bigIcon.Value);
+ }
+ }
+
+ private void SetWindowSize(HWND hwnd, int width, int height)
+ {
+ // Win32 uses pixels and WinUI 3 uses effective pixels, so you should apply the DPI scale factor
+ uint dpi = GetDpiForWindow(hwnd);
+ float scalingFactor = (float)dpi / 96;
+ width = (int)(width * scalingFactor);
+ height = (int)(height * scalingFactor);
+
+ SetWindowPos(hwnd, default, 0, 0, width, height, SET_WINDOW_POS_FLAGS.SWP_NOMOVE | SET_WINDOW_POS_FLAGS.SWP_NOZORDER);
+ }
+
+ private void PlacementCenterWindowInMonitorWin32(HWND hwnd)
+ {
+ RECT windowMonitorRectToAdjust;
+ GetWindowRect(hwnd, out windowMonitorRectToAdjust);
+ ClipOrCenterRectToMonitorWin32(ref windowMonitorRectToAdjust);
+ SetWindowPos(hwnd, default, windowMonitorRectToAdjust.left,
+ windowMonitorRectToAdjust.top, 0, 0,
+ SET_WINDOW_POS_FLAGS.SWP_NOSIZE |
+ SET_WINDOW_POS_FLAGS.SWP_NOZORDER |
+ SET_WINDOW_POS_FLAGS.SWP_NOACTIVATE);
+ }
+
+ private void ClipOrCenterRectToMonitorWin32(ref RECT adjustedWindowRect)
+ {
+ MONITORINFO mi = new MONITORINFO();
+ mi.cbSize = (uint)Marshal.SizeOf();
+ GetMonitorInfo(MonitorFromRect(adjustedWindowRect, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST), ref mi);
+
+ RECT rcWork = mi.rcWork;
+ int w = adjustedWindowRect.right - adjustedWindowRect.left;
+ int h = adjustedWindowRect.bottom - adjustedWindowRect.top;
+
+ adjustedWindowRect.left = rcWork.left + (rcWork.right - rcWork.left - w) / 2;
+ adjustedWindowRect.top = rcWork.top + (rcWork.bottom - rcWork.top - h) / 2;
+ adjustedWindowRect.right = adjustedWindowRect.left + w;
+ adjustedWindowRect.bottom = adjustedWindowRect.top + h;
+ }
+ }
+}
diff --git a/Samples/CustomControls/CsApp/NativeMethods.txt b/Samples/CustomControls/CsApp/NativeMethods.txt
new file mode 100644
index 000000000..d5596147d
--- /dev/null
+++ b/Samples/CustomControls/CsApp/NativeMethods.txt
@@ -0,0 +1,12 @@
+GetDpiForWindow
+GetModuleHandle
+GetMonitorInfo
+GetSystemMetrics
+GetWindowRect
+LoadImage
+MONITORINFO
+MonitorFromRect
+RECT
+SendMessage
+SetWindowPos
+WM_SETICON
diff --git a/Samples/CustomControls/CsApp/Package.appxmanifest b/Samples/CustomControls/CsApp/Package.appxmanifest
new file mode 100644
index 000000000..f89e139c2
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Package.appxmanifest
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+ CsApp
+ Microsoft Corporation
+ Assets\logo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-arm64.pubxml b/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-arm64.pubxml
new file mode 100644
index 000000000..93f661786
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-arm64.pubxml
@@ -0,0 +1,19 @@
+
+
+
+
+ FileSystem
+ arm64
+ win10-arm64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-x64.pubxml b/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-x64.pubxml
new file mode 100644
index 000000000..26ea7e55c
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-x64.pubxml
@@ -0,0 +1,20 @@
+
+
+
+
+ FileSystem
+ x64
+ win10-x64
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-x86.pubxml b/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-x86.pubxml
new file mode 100644
index 000000000..34d14d4d4
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Properties/PublishProfiles/win10-x86.pubxml
@@ -0,0 +1,20 @@
+
+
+
+
+ FileSystem
+ x86
+ win10-x86
+ bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\
+ true
+ False
+ False
+ True
+
+
+
\ No newline at end of file
diff --git a/Samples/CustomControls/CsApp/Properties/launchSettings.json b/Samples/CustomControls/CsApp/Properties/launchSettings.json
new file mode 100644
index 000000000..c75cf04da
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Properties/launchSettings.json
@@ -0,0 +1,10 @@
+{
+ "profiles": {
+ "CsApp (Package)": {
+ "commandName": "MsixPackage"
+ },
+ "CsApp (Unpackaged)": {
+ "commandName": "Project"
+ }
+ }
+}
\ No newline at end of file
diff --git a/Samples/CustomControls/CsApp/SampleConfiguration.cs b/Samples/CustomControls/CsApp/SampleConfiguration.cs
new file mode 100644
index 000000000..676089b54
--- /dev/null
+++ b/Samples/CustomControls/CsApp/SampleConfiguration.cs
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using System.Collections.Generic;
+
+namespace CsApp
+{
+ internal static class SampleConfig
+ {
+ public const string FeatureName = "CsApp";
+ public static ElementTheme CurrentTheme = ElementTheme.Default;
+ }
+
+ public partial class MainPage : Page
+ {
+ private readonly List scenarios = new()
+ {
+ new Scenario() { Title = "Custom Control", ClassName = typeof(Scenario1_CustomControl).FullName },
+ new Scenario() { Title = "User Control", ClassName = typeof(Scenario2_UserControl).FullName }
+ };
+ }
+
+ public class Scenario
+ {
+ public string Title { get; set; }
+ public string ClassName { get; set; }
+ }
+}
diff --git a/Samples/CustomControls/CsApp/Scenario1_CustomControl.xaml b/Samples/CustomControls/CsApp/Scenario1_CustomControl.xaml
new file mode 100644
index 000000000..eda5082af
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Scenario1_CustomControl.xaml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+ Reference a Custom WinUI Button type from a C# component.
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/Scenario1_CustomControl.xaml.cs b/Samples/CustomControls/CsApp/Scenario1_CustomControl.xaml.cs
new file mode 100644
index 000000000..58c1bddd2
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Scenario1_CustomControl.xaml.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace CsApp
+{
+ public partial class Scenario1_CustomControl : Page
+ {
+ private MainPage rootPage = MainPage.Current;
+
+ public Scenario1_CustomControl()
+ {
+ this.InitializeComponent();
+ }
+
+ }
+}
diff --git a/Samples/CustomControls/CsApp/Scenario2_UserControl.xaml b/Samples/CustomControls/CsApp/Scenario2_UserControl.xaml
new file mode 100644
index 000000000..63a3d61ef
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Scenario2_UserControl.xaml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Reference a Custom User Control from a C# Component.
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/Scenario2_UserControl.xaml.cs b/Samples/CustomControls/CsApp/Scenario2_UserControl.xaml.cs
new file mode 100644
index 000000000..cdeed77c6
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Scenario2_UserControl.xaml.cs
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.UI.Xaml.Controls;
+
+namespace CsApp
+{
+ public partial class Scenario2_UserControl : Page
+ {
+ public Scenario2_UserControl()
+ {
+ this.InitializeComponent();
+ }
+ }
+}
diff --git a/Samples/CustomControls/CsApp/SettingsPage.xaml b/Samples/CustomControls/CsApp/SettingsPage.xaml
new file mode 100644
index 000000000..bb8090017
--- /dev/null
+++ b/Samples/CustomControls/CsApp/SettingsPage.xaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+ Light
+
+
+
+
+ Dark
+
+
+
+
+ Default
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/SettingsPage.xaml.cs b/Samples/CustomControls/CsApp/SettingsPage.xaml.cs
new file mode 100644
index 000000000..d244b0650
--- /dev/null
+++ b/Samples/CustomControls/CsApp/SettingsPage.xaml.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Navigation;
+using System.Linq;
+
+namespace CsApp
+{
+ public partial class SettingsPage : Page
+ {
+ public SettingsPage()
+ {
+ this.InitializeComponent();
+ }
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ themePanel.Children.Cast().First(c => (ElementTheme)c.Tag == SampleConfig.CurrentTheme).IsChecked = true;
+ base.OnNavigatedTo(e);
+ }
+
+ private void OnThemeRadioButtonChecked(object sender, RoutedEventArgs e)
+ {
+ ElementTheme selectedTheme = (ElementTheme)((RadioButton)sender).Tag;
+
+ Grid content = MainPage.Current.Content as Grid;
+ if (content is not null)
+ {
+ content.RequestedTheme = selectedTheme;
+ SampleConfig.CurrentTheme = content.RequestedTheme;
+ }
+ }
+ }
+}
diff --git a/Samples/CustomControls/CsApp/Styles.xaml b/Samples/CustomControls/CsApp/Styles.xaml
new file mode 100644
index 000000000..e79221750
--- /dev/null
+++ b/Samples/CustomControls/CsApp/Styles.xaml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/CsApp/app.manifest b/Samples/CustomControls/CsApp/app.manifest
new file mode 100644
index 000000000..f9e21aa55
--- /dev/null
+++ b/Samples/CustomControls/CsApp/app.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+ true/PM
+ PerMonitorV2, PerMonitor
+
+
+
diff --git a/Samples/CustomControls/CsWinRTAuthoringWinUI.sln b/Samples/CustomControls/CsWinRTAuthoringWinUI.sln
new file mode 100644
index 000000000..ba27c4622
--- /dev/null
+++ b/Samples/CustomControls/CsWinRTAuthoringWinUI.sln
@@ -0,0 +1,97 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32126.317
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppApp", "CppApp\CppApp.vcxproj", "{34A4AD19-A703-47F3-B279-E505C6A2A935}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CsApp", "CsApp\CsApp.csproj", "{4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CppAppUnpackaged", "CppAppUnpackaged\CppAppUnpackaged.vcxproj", "{B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinUIComponentCs", "WinUIComponentCs\WinUIComponentCs.csproj", "{BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|arm64 = Debug|arm64
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|arm64 = Release|arm64
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|arm64.ActiveCfg = Debug|arm64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|arm64.Build.0 = Debug|arm64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|arm64.Deploy.0 = Debug|arm64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|x64.ActiveCfg = Debug|x64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|x64.Build.0 = Debug|x64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|x64.Deploy.0 = Debug|x64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|x86.ActiveCfg = Debug|Win32
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|x86.Build.0 = Debug|Win32
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Debug|x86.Deploy.0 = Debug|Win32
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|arm64.ActiveCfg = Release|arm64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|arm64.Build.0 = Release|arm64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|arm64.Deploy.0 = Release|arm64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|x64.ActiveCfg = Release|x64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|x64.Build.0 = Release|x64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|x64.Deploy.0 = Release|x64
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|x86.ActiveCfg = Release|Win32
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|x86.Build.0 = Release|Win32
+ {34A4AD19-A703-47F3-B279-E505C6A2A935}.Release|x86.Deploy.0 = Release|Win32
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Debug|arm64.ActiveCfg = Debug|Any CPU
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Debug|arm64.Build.0 = Debug|Any CPU
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Debug|x64.ActiveCfg = Debug|x64
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Debug|x64.Build.0 = Debug|x64
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Debug|x86.ActiveCfg = Debug|x86
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Debug|x86.Build.0 = Debug|x86
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Release|arm64.ActiveCfg = Release|Any CPU
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Release|arm64.Build.0 = Release|Any CPU
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Release|x64.ActiveCfg = Release|Any CPU
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Release|x64.Build.0 = Release|Any CPU
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Release|x86.ActiveCfg = Release|Any CPU
+ {BCC816DC-0F01-4F0F-8506-DF6AFEFAEA92}.Release|x86.Build.0 = Release|Any CPU
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|arm64.ActiveCfg = Debug|arm64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|arm64.Build.0 = Debug|arm64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|arm64.Deploy.0 = Debug|arm64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|x64.ActiveCfg = Debug|x64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|x64.Build.0 = Debug|x64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|x64.Deploy.0 = Debug|x64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|x86.ActiveCfg = Debug|x86
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|x86.Build.0 = Debug|x86
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Debug|x86.Deploy.0 = Debug|x86
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|arm64.ActiveCfg = Release|arm64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|arm64.Build.0 = Release|arm64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|arm64.Deploy.0 = Release|arm64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|x64.ActiveCfg = Release|x64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|x64.Build.0 = Release|x64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|x64.Deploy.0 = Release|x64
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|x86.ActiveCfg = Release|x86
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|x86.Build.0 = Release|x86
+ {4B4FA4E7-D50E-4059-A906-6F78F6DFEBCD}.Release|x86.Deploy.0 = Release|x86
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|arm64.ActiveCfg = Debug|arm64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|arm64.Build.0 = Debug|arm64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|arm64.Deploy.0 = Debug|arm64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|x64.ActiveCfg = Debug|x64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|x64.Build.0 = Debug|x64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|x64.Deploy.0 = Debug|x64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|x86.ActiveCfg = Debug|Win32
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|x86.Build.0 = Debug|Win32
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Debug|x86.Deploy.0 = Debug|Win32
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|arm64.ActiveCfg = Release|arm64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|arm64.Build.0 = Release|arm64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|arm64.Deploy.0 = Release|arm64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|x64.ActiveCfg = Release|x64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|x64.Build.0 = Release|x64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|x64.Deploy.0 = Release|x64
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|x86.ActiveCfg = Release|Win32
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|x86.Build.0 = Release|Win32
+ {B71D15EF-F17B-4E8F-B023-08C4E3B32DAB}.Release|x86.Deploy.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {EF6C20C8-AA97-4F17-A329-7A96FC162EAD}
+ EndGlobalSection
+EndGlobal
diff --git a/Samples/CustomControls/README.md b/Samples/CustomControls/README.md
new file mode 100644
index 000000000..9a9e5c32f
--- /dev/null
+++ b/Samples/CustomControls/README.md
@@ -0,0 +1,42 @@
+---
+page_type: sample
+languages:
+- cpp
+- csharp
+products:
+- windows
+- windows-app-sdk
+name: "C# Windows Runtime Component WinUI Controls Sample"
+urlFragment: csruntimecomponent
+description: "Shows how to author a Windows Runtime Component in C# with WinUI controls and how to consume it from C++ and C#."
+extendedZipContent:
+- path: LICENSE
+ target: LICENSE
+---
+# Custom Controls Sample (C# Windows Runtime Component)
+
+This sample demonstrates how to author C# components with WinUI controls (User Control and Custom Control) using C#/WinRT, and how to consume these components from C++ and C# apps.
+
+The sample solution includes the following application projects:
+
+- **CppApp** (packaged C++ WinUI app)
+- **CppAppUnpackaged** (unpackaged C++ WinUI app)
+- **CsApp** (packaged C# WinUI app)
+
+All the application projects have a project reference to the C# Windows Runtime component library project, **WinUICsComponent**. The C# component uses the *Microsoft.Windows.CsWinRT* NuGet package to generate a Windows Runtime Component with custom WinUI controls.
+
+## Prerequisites
+
+* See [System requirements for Windows app development](https://docs.microsoft.com/windows/apps/windows-app-sdk/system-requirements).
+* Make sure that your development environment is set up correctly—see [Install tools for developing apps for Windows 10 and Windows 11](https://docs.microsoft.com/windows/apps/windows-app-sdk/set-up-your-development-environment).
+
+## Building and running the sample
+
+* Open the solution file (`.sln`) in Visual Studio.
+* Set one of the application projects as the startup project.
+* Select `x86` as the Solution platform. There is a known issue with `x64` and `arm64` (https://github.com/microsoft/CsWinRT/issues/1093).
+* From Visual Studio, either **Start Without Debugging** (Ctrl+F5) or **Start Debugging** (F5).
+
+## Related Links
+
+- [C#/WinRT Authoring](https://github.com/microsoft/CsWinRT/blob/master/docs/authoring.md)
diff --git a/Samples/CustomControls/WinUIComponentCs/CustomButton.cs b/Samples/CustomControls/WinUIComponentCs/CustomButton.cs
new file mode 100644
index 000000000..dd98b3368
--- /dev/null
+++ b/Samples/CustomControls/WinUIComponentCs/CustomButton.cs
@@ -0,0 +1,70 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Documents;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using Windows.Foundation;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace WinUIComponentCs
+{
+ public sealed class CustomButton : Button
+ {
+ public string Text { get; private set; }
+ public bool OverrideEntered { get; set; }
+
+ public CustomButton()
+ : this("CustomButton")
+ {
+ }
+
+ public CustomButton(string text)
+ {
+ Text = text;
+ Content = text;
+ OverrideEntered = true;
+ }
+
+ protected override void OnPointerEntered(global::Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
+ {
+ if (!OverrideEntered)
+ {
+ base.OnPointerEntered(e);
+ return;
+ }
+
+ Text = Content?.ToString();
+ Content = "Entered";
+ }
+
+ protected override void OnPointerExited(global::Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
+ {
+ if (!OverrideEntered)
+ {
+ base.OnPointerExited(e);
+ return;
+ }
+
+ Content = Text;
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ var size = new Size(160, 30);
+ base.MeasureOverride(size);
+ return size;
+ }
+
+ public string GetText()
+ {
+ return Text;
+ }
+ }
+}
diff --git a/Samples/CustomControls/WinUIComponentCs/NameReporter.xaml b/Samples/CustomControls/WinUIComponentCs/NameReporter.xaml
new file mode 100644
index 000000000..11ae225d1
--- /dev/null
+++ b/Samples/CustomControls/WinUIComponentCs/NameReporter.xaml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+ First Name:
+
+
+
+
+
+ Last Name:
+
+
+
+
+
+
+
diff --git a/Samples/CustomControls/WinUIComponentCs/NameReporter.xaml.cs b/Samples/CustomControls/WinUIComponentCs/NameReporter.xaml.cs
new file mode 100644
index 000000000..0c77603f9
--- /dev/null
+++ b/Samples/CustomControls/WinUIComponentCs/NameReporter.xaml.cs
@@ -0,0 +1,36 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Controls.Primitives;
+using Microsoft.UI.Xaml.Data;
+using Microsoft.UI.Xaml.Input;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Navigation;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Text;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+
+// To learn more about WinUI, the WinUI project structure,
+// and more about our project templates, see: http://aka.ms/winui-project-info.
+
+namespace WinUIComponentCs
+{
+ public sealed partial class NameReporter : UserControl
+ {
+ public NameReporter()
+ {
+ this.InitializeComponent();
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ StringBuilder displayText = new StringBuilder("Hello, ");
+ displayText.AppendFormat("{0} {1}.", firstName.Text, lastName.Text);
+ result.Text = displayText.ToString();
+ }
+ }
+}
diff --git a/Samples/CustomControls/WinUIComponentCs/WinUIComponentCs.csproj b/Samples/CustomControls/WinUIComponentCs/WinUIComponentCs.csproj
new file mode 100644
index 000000000..05df72b0b
--- /dev/null
+++ b/Samples/CustomControls/WinUIComponentCs/WinUIComponentCs.csproj
@@ -0,0 +1,25 @@
+
+
+ net6.0-windows10.0.19041.0
+ 10.0.17763.0
+ WinUIComponentCs
+ win10-x86;win10-x64;win10-arm64
+ true
+ true
+ x64;x86;arm64
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+
+
+
+
diff --git a/SamplesCI-CustomControls.yml b/SamplesCI-CustomControls.yml
new file mode 100644
index 000000000..b7cec7900
--- /dev/null
+++ b/SamplesCI-CustomControls.yml
@@ -0,0 +1,7 @@
+# Please see https://www.osgwiki.com/wiki/Windows_App_SDK_-_How_to_build_and_use_the_pipelines
+# for information on how to use the pipelines
+name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
+stages:
+- template: WindowsAppSDK-SamplesCI.yml
+ parameters:
+ FeatureDirectory: "CustomControls"