diff --git a/WinUIGallery/App.xaml b/WinUIGallery/App.xaml
index 39293dfa1..e0e2d8e3d 100644
--- a/WinUIGallery/App.xaml
+++ b/WinUIGallery/App.xaml
@@ -25,6 +25,8 @@
+
+
diff --git a/WinUIGallery/Pages/NavigationRootPage.xaml b/WinUIGallery/Pages/NavigationRootPage.xaml
index b21d710ee..31c77a068 100644
--- a/WinUIGallery/Pages/NavigationRootPage.xaml
+++ b/WinUIGallery/Pages/NavigationRootPage.xaml
@@ -216,6 +216,11 @@
AutomationProperties.AutomationId="Templates"
Content="Templates"
Tag="Templates" />
+
(int)GetValue(CountProperty);
+ set => SetValue(CountProperty, value);
+ }
+
+ public CounterMode Mode
+ {
+ get => (CounterMode)GetValue(ModeProperty);
+ set => SetValue(ModeProperty, value);
+ }
+
+ private Button ActionButton;
+ private TextBlock CountText;
+
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ ActionButton = GetTemplateChild(nameof(ActionButton)) as Button;
+ CountText = GetTemplateChild(nameof(CountText)) as TextBlock;
+
+ if (ActionButton is not null)
+ {
+ ActionButton.Click += (sender, e) =>
+ {
+ Count = Mode == CounterMode.Increment ? Count + 1 : Count - 1;
+ UpdateUI();
+ };
+
+ UpdateButtonText();
+ }
+
+ UpdateUI();
+ }
+
+ private void UpdateUI()
+ {
+ if (CountText is not null)
+ {
+ CountText.Text = Count.ToString();
+ }
+ }
+
+ private void UpdateButtonText()
+ {
+ if (ActionButton is not null)
+ {
+ ActionButton.Content = Mode == CounterMode.Increment ? "Increase" : "Decrease";
+ }
+ }
+}
+
diff --git a/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/CounterControl.xaml b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/CounterControl.xaml
new file mode 100644
index 000000000..4ab127aea
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/CounterControl.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+
diff --git a/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/TemperatureConverterControl.xaml b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/TemperatureConverterControl.xaml
new file mode 100644
index 000000000..1125d7b92
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/TemperatureConverterControl.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
diff --git a/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/TemperatureConverterControl.xaml.cs b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/TemperatureConverterControl.xaml.cs
new file mode 100644
index 000000000..9c86c6988
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/TemperatureConverterControl.xaml.cs
@@ -0,0 +1,30 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace WinUIGallery.Samples.ControlPages.Fundamentals.Controls;
+
+public sealed partial class TemperatureConverterControl : UserControl
+{
+ public TemperatureConverterControl()
+ {
+ this.InitializeComponent();
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ string input = InputTextBox.Text;
+ double celsius = 0;
+
+ bool isNumber = double.TryParse(input, out celsius);
+
+ if (isNumber)
+ {
+ double fahrenheit = (celsius * 9 / 5) + 32;
+ ResultTextBlock.Text = "Fahrenheit: " + fahrenheit.ToString("F2") + "°F";
+ }
+ else
+ {
+ ResultTextBlock.Text = "Invalid input!";
+ }
+ }
+}
diff --git a/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/ValidatedPasswordBox.cs b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/ValidatedPasswordBox.cs
new file mode 100644
index 000000000..6cf7d9da7
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/ValidatedPasswordBox.cs
@@ -0,0 +1,128 @@
+using System.Linq;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace WinUIGallery.Samples.ControlPages.Fundamentals.Controls;
+
+public sealed class ValidatedPasswordBox : Control
+{
+ public static readonly DependencyProperty PasswordProperty =
+ DependencyProperty.Register(nameof(Password), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));
+
+ public static readonly DependencyProperty IsValidProperty =
+ DependencyProperty.Register(nameof(IsValid), typeof(bool), typeof(ValidatedPasswordBox), new PropertyMetadata(false));
+
+ public static readonly DependencyProperty MinLengthProperty =
+ DependencyProperty.Register(nameof(MinLength), typeof(int), typeof(ValidatedPasswordBox), new PropertyMetadata(8, OnPasswordChanged));
+
+ public static readonly DependencyProperty HeaderProperty =
+ DependencyProperty.Register(nameof(Header), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));
+
+ public static readonly DependencyProperty PlaceholderTextProperty =
+ DependencyProperty.Register(nameof(PlaceholderText), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));
+
+ public ValidatedPasswordBox()
+ {
+ this.DefaultStyleKey = typeof(ValidatedPasswordBox);
+ }
+
+ public string Password
+ {
+ get => (string)GetValue(PasswordProperty);
+ set => SetValue(PasswordProperty, value);
+ }
+
+ public bool IsValid
+ {
+ get => (bool)GetValue(IsValidProperty);
+ set => SetValue(IsValidProperty, value);
+ }
+
+ public int MinLength
+ {
+ get => (int)GetValue(MinLengthProperty);
+ set => SetValue(MinLengthProperty, value);
+ }
+
+ public string Header
+ {
+ get => (string)GetValue(HeaderProperty);
+ set => SetValue(HeaderProperty, value);
+ }
+
+ public string PlaceholderText
+ {
+ get => (string)GetValue(PlaceholderTextProperty);
+ set => SetValue(PlaceholderTextProperty, value);
+ }
+
+ private PasswordBox PasswordInput { get; set; }
+ private StackPanel MissingUppercaseText { get; set; }
+ private StackPanel MissingNumberText { get; set; }
+ private StackPanel TooShortText { get; set; }
+ private StackPanel ValidPasswordText { get; set; }
+
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ PasswordInput = GetTemplateChild(nameof(PasswordInput)) as PasswordBox;
+ if (PasswordInput != null)
+ {
+ PasswordInput.Header = Header;
+ PasswordInput.PlaceholderText = PlaceholderText;
+ }
+
+ MissingUppercaseText = GetTemplateChild(nameof(MissingUppercaseText)) as StackPanel;
+ MissingNumberText = GetTemplateChild(nameof(MissingNumberText)) as StackPanel;
+ TooShortText = GetTemplateChild(nameof(TooShortText)) as StackPanel;
+ ValidPasswordText = GetTemplateChild(nameof(ValidPasswordText)) as StackPanel;
+
+ if (PasswordInput is not null)
+ {
+ PasswordInput.PasswordChanged += (sender, e) =>
+ {
+ Password = PasswordInput.Password;
+ UpdateValidationMessages();
+ };
+ }
+
+ UpdateValidationMessages();
+ }
+
+ private static void OnPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var control = (ValidatedPasswordBox)d;
+ control.UpdateValidationMessages();
+ }
+
+ private void UpdateValidationMessages()
+ {
+ bool hasMinLength = Password.Length >= MinLength;
+ bool hasUppercase = Password.Any(char.IsUpper);
+ bool hasNumber = Password.Any(char.IsDigit);
+
+ IsValid = hasMinLength && hasUppercase && hasNumber;
+
+ if (MissingUppercaseText is not null)
+ {
+ MissingUppercaseText.Visibility = (hasUppercase || string.IsNullOrEmpty(Password)) ? Visibility.Collapsed : Visibility.Visible;
+ }
+
+ if (MissingNumberText is not null)
+ {
+ MissingNumberText.Visibility = (hasNumber || string.IsNullOrEmpty(Password)) ? Visibility.Collapsed : Visibility.Visible;
+ }
+
+ if (TooShortText is not null)
+ {
+ TooShortText.Visibility = (hasMinLength || string.IsNullOrEmpty(Password)) ? Visibility.Collapsed : Visibility.Visible;
+ }
+
+ if (ValidPasswordText is not null)
+ {
+ ValidPasswordText.Visibility = IsValid ? Visibility.Visible : Visibility.Collapsed;
+ }
+ }
+}
+
diff --git a/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/ValidatedPasswordBox.xaml b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/ValidatedPasswordBox.xaml
new file mode 100644
index 000000000..339e4bb92
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/Fundamentals/Controls/ValidatedPasswordBox.xaml
@@ -0,0 +1,62 @@
+
+
+
+
+
diff --git a/WinUIGallery/Samples/ControlPages/Fundamentals/CustomUserControlsPage.xaml b/WinUIGallery/Samples/ControlPages/Fundamentals/CustomUserControlsPage.xaml
new file mode 100644
index 000000000..57e73dcae
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/Fundamentals/CustomUserControlsPage.xaml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ • Encapsulation: custom controls encapsulate behavior and UI logic, making them reusable across different projects.
+ • Theming: they support light and dark themes through theme resources.
+
+
+
+ Key points
+ • Use
+ file or a new
+ to define the default style of a custom control.
+
+
+ • Override
+ to interact with template parts.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/WinUIGallery/Samples/ControlPages/Fundamentals/CustomUserControlsPage.xaml.cs b/WinUIGallery/Samples/ControlPages/Fundamentals/CustomUserControlsPage.xaml.cs
new file mode 100644
index 000000000..c80c8e6ac
--- /dev/null
+++ b/WinUIGallery/Samples/ControlPages/Fundamentals/CustomUserControlsPage.xaml.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using Microsoft.UI.Xaml.Controls;
+
+namespace WinUIGallery.ControlPages;
+
+public sealed partial class CustomUserControlsPage : Page
+{
+ public CustomUserControlsPage()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/WinUIGallery/Samples/Data/ControlInfoData.json b/WinUIGallery/Samples/Data/ControlInfoData.json
index 04084f273..5c875b0bf 100644
--- a/WinUIGallery/Samples/Data/ControlInfoData.json
+++ b/WinUIGallery/Samples/Data/ControlInfoData.json
@@ -110,6 +110,34 @@
}
]
},
+ {
+ "UniqueId": "CustomUserControls",
+ "Title": "Custom & User Controls",
+ "Subtitle": "Create reusable UI components with custom functionality and appearance.",
+ "BaseClasses": [
+ "Object",
+ "DependencyObject",
+ "FrameworkElement",
+ "Control"
+ ],
+ "ApiNamespace": "Microsoft.UI.Xaml.Controls",
+ "ImagePath": "ms-appx:///Assets/ControlImages/CustomControlsIcon.png",
+ "Description": "Custom controls and user controls allow to create reusable UI components with unique behavior and styling. A UserControl is a simple way to encapsulate a UI layout, while a custom control provides full styling and templating flexibility. Both approaches help in building modular and maintainable applications.",
+ "Docs": [
+ {
+ "Title": "Build XAML controls",
+ "Uri": "https://learn.microsoft.com/windows/apps/winui/winui3/xaml-templated-controls-csharp-winui-3"
+ },
+ {
+ "Title": "Control - API",
+ "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.control"
+ },
+ {
+ "Title": "UserControl - API",
+ "Uri": "https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.controls.usercontrol"
+ }
+ ]
+ },
{
"UniqueId": "ScratchPad",
"Title": "Scratch Pad",
diff --git a/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample1_cs.txt b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample1_cs.txt
new file mode 100644
index 000000000..3a11ddfb1
--- /dev/null
+++ b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample1_cs.txt
@@ -0,0 +1,88 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace YourNamespace;
+
+// Enum defining the counter mode: Increment or Decrement
+public enum CounterMode
+{
+ Increment,
+ Decrement
+}
+
+// Custom control class that extends Control
+public sealed class CounterControl : Control
+{
+ // DependencyProperty for storing the count value
+ public static readonly DependencyProperty CountProperty =
+ DependencyProperty.Register(nameof(Count), typeof(int), typeof(CounterControl), new PropertyMetadata(0));
+
+ // DependencyProperty for determining the counter mode (Increment or Decrement)
+ public static readonly DependencyProperty ModeProperty =
+ DependencyProperty.Register(nameof(Mode), typeof(CounterMode), typeof(CounterControl), new PropertyMetadata(CounterMode.Increment));
+
+ // Constructor setting the default style key
+ public CounterControl()
+ {
+ this.DefaultStyleKey = typeof(CounterControl);
+ }
+
+ // Property to get and set the count value
+ public int Count
+ {
+ get => (int)GetValue(CountProperty);
+ set => SetValue(CountProperty, value);
+ }
+
+ // Property to get and set the counter mode
+ public CounterMode Mode
+ {
+ get => (CounterMode)GetValue(ModeProperty);
+ set => SetValue(ModeProperty, value);
+ }
+
+ // Fields for UI elements retrieved from the control template
+ private Button ActionButton;
+ private TextBlock CountText;
+
+ // Method executed when the control's template is applied
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ // Retrieve template elements
+ ActionButton = GetTemplateChild(nameof(ActionButton)) as Button;
+ CountText = GetTemplateChild(nameof(CountText)) as TextBlock;
+
+ // Attach event handler to button if it exists
+ if (ActionButton is not null)
+ {
+ ActionButton.Click += (sender, e) =>
+ {
+ Count = Mode == CounterMode.Increment ? Count + 1 : Count - 1;
+ UpdateUI();
+ };
+
+ UpdateButtonText();
+ }
+
+ UpdateUI();
+ }
+
+ private void UpdateUI()
+ {
+ if (CountText is not null)
+ {
+ CountText.Text = Count.ToString();
+ }
+ }
+
+ private void UpdateButtonText()
+ {
+ if (ActionButton is not null)
+ {
+ ActionButton.Content = Mode == CounterMode.Increment ? "Increase" : "Decrease";
+ }
+ }
+}
+
diff --git a/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample1_xaml.txt b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample1_xaml.txt
new file mode 100644
index 000000000..d88fe70fe
--- /dev/null
+++ b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample1_xaml.txt
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample2_cs.txt b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample2_cs.txt
new file mode 100644
index 000000000..7872ab363
--- /dev/null
+++ b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample2_cs.txt
@@ -0,0 +1,94 @@
+using System.Linq;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace YourNamespace;
+
+// Custom control for a validated password box
+public sealed class ValidatedPasswordBox : Control
+{
+ // Register a dependency property for the Password value.
+ // Note: The PropertyMetadata includes a callback (OnPasswordChanged) so that the UI updates
+ // whenever the password or related properties change.
+ public static readonly DependencyProperty PasswordProperty =
+ DependencyProperty.Register(nameof(Password), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));
+
+ public static readonly DependencyProperty IsValidProperty =
+ DependencyProperty.Register(nameof(IsValid), typeof(bool), typeof(ValidatedPasswordBox), new PropertyMetadata(false));
+
+ public static readonly DependencyProperty MinLengthProperty =
+ DependencyProperty.Register(nameof(MinLength), typeof(int), typeof(ValidatedPasswordBox), new PropertyMetadata(8, OnPasswordChanged));
+
+ public static readonly DependencyProperty HeaderProperty =
+ DependencyProperty.Register(nameof(Header), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));
+
+ public static readonly DependencyProperty PlaceholderTextProperty =
+ DependencyProperty.Register(nameof(PlaceholderText), typeof(string), typeof(ValidatedPasswordBox), new PropertyMetadata(string.Empty, OnPasswordChanged));
+
+ public ValidatedPasswordBox()
+ {
+ this.DefaultStyleKey = typeof(ValidatedPasswordBox);
+ }
+
+ // CLR property wrappers
+ public string Password { get => (string)GetValue(PasswordProperty); set => SetValue(PasswordProperty, value); }
+ public bool IsValid { get => (bool)GetValue(IsValidProperty); set => SetValue(IsValidProperty, value); }
+ public int MinLength { get => (int)GetValue(MinLengthProperty); set => SetValue(MinLengthProperty, value); }
+ public string Header { get => (string)GetValue(HeaderProperty); set => SetValue(HeaderProperty, value); }
+ public string PlaceholderText { get => (string)GetValue(PlaceholderTextProperty); set => SetValue(PlaceholderTextProperty, value); }
+
+ // Template parts for password input and validation messages
+ private PasswordBox PasswordInput { get; set; }
+ private StackPanel MissingUppercaseText { get; set; }
+ private StackPanel MissingNumberText { get; set; }
+ private StackPanel TooShortText { get; set; }
+ private StackPanel ValidPasswordText { get; set; }
+
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ PasswordInput = GetTemplateChild(nameof(PasswordInput)) as PasswordBox;
+ if (PasswordInput != null)
+ {
+ PasswordInput.Header = Header;
+ PasswordInput.PlaceholderText = PlaceholderText;
+ PasswordInput.PasswordChanged += (sender, e) =>
+ {
+ Password = PasswordInput.Password;
+ UpdateValidationMessages();
+ };
+ }
+
+ MissingUppercaseText = GetTemplateChild(nameof(MissingUppercaseText)) as StackPanel;
+ MissingNumberText = GetTemplateChild(nameof(MissingNumberText)) as StackPanel;
+ TooShortText = GetTemplateChild(nameof(TooShortText)) as StackPanel;
+ ValidPasswordText = GetTemplateChild(nameof(ValidPasswordText)) as StackPanel;
+
+ UpdateValidationMessages();
+ }
+
+ private static void OnPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ ((ValidatedPasswordBox)d).UpdateValidationMessages();
+ }
+
+ // Update UI elements based on current password validation
+ private void UpdateValidationMessages()
+ {
+ bool hasMinLength = Password.Length >= MinLength;
+ bool hasUppercase = Password.Any(char.IsUpper);
+ bool hasNumber = Password.Any(char.IsDigit);
+
+ IsValid = hasMinLength && hasUppercase && hasNumber;
+
+ if (MissingUppercaseText != null)
+ MissingUppercaseText.Visibility = (hasUppercase || string.IsNullOrEmpty(Password)) ? Visibility.Collapsed : Visibility.Visible;
+ if (MissingNumberText != null)
+ MissingNumberText.Visibility = (hasNumber || string.IsNullOrEmpty(Password)) ? Visibility.Collapsed : Visibility.Visible;
+ if (TooShortText != null)
+ TooShortText.Visibility = (hasMinLength || string.IsNullOrEmpty(Password)) ? Visibility.Collapsed : Visibility.Visible;
+ if (ValidPasswordText != null)
+ ValidPasswordText.Visibility = IsValid ? Visibility.Visible : Visibility.Collapsed;
+ }
+}
diff --git a/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample2_xaml.txt b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample2_xaml.txt
new file mode 100644
index 000000000..856283768
--- /dev/null
+++ b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample2_xaml.txt
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample3_cs.txt b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample3_cs.txt
new file mode 100644
index 000000000..879c3960f
--- /dev/null
+++ b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample3_cs.txt
@@ -0,0 +1,30 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace YourNamesapace;
+
+public sealed partial class TemperatureConverterControl : UserControl
+{
+ public TemperatureConverterControl()
+ {
+ this.InitializeComponent();
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ string input = InputTextBox.Text;
+ double celsius = 0;
+
+ bool isNumber = double.TryParse(input, out celsius);
+
+ if (isNumber)
+ {
+ double fahrenheit = (celsius * 9 / 5) + 32;
+ ResultTextBlock.Text = "Fahrenheit: " + fahrenheit.ToString("F2") + "°F";
+ }
+ else
+ {
+ ResultTextBlock.Text = "Invalid input!";
+ }
+ }
+}
diff --git a/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample3_xaml.txt b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample3_xaml.txt
new file mode 100644
index 000000000..f0d3ab7a7
--- /dev/null
+++ b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample3_xaml.txt
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample4_cs.txt b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample4_cs.txt
new file mode 100644
index 000000000..f3d956da4
--- /dev/null
+++ b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample4_cs.txt
@@ -0,0 +1,74 @@
+using System.Collections.Generic;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+using Windows.System;
+
+namespace YourNamesapce;
+
+public sealed partial class SynonymFinderControl : UserControl
+ {
+ public Dictionary> SynonymsSource { get; set; } = new();
+ public string Header { get; set; } = string.Empty;
+
+ public SynonymFinderControl()
+ {
+ this.InitializeComponent();
+ }
+
+ private void InputTextBox_KeyDown(object sender, KeyRoutedEventArgs e)
+ {
+ if (e.Key == VirtualKey.Enter)
+ {
+ FindSynonyms();
+ }
+ }
+
+ private void FindButton_Click(object sender, RoutedEventArgs e)
+ {
+ FindSynonyms();
+ }
+
+ private void FindSynonyms()
+ {
+ if (SynonymsSource == null)
+ {
+ return;
+ }
+
+ string key = InputTextBox.Text.Trim();
+ if (SynonymsSource.TryGetValue(key, out var synonyms))
+ {
+ SynonymsList.ItemsSource = synonyms;
+ }
+ else
+ {
+ SynonymsList.ItemsSource = new List { $"No synonyms found for \"{key}\"" };
+ }
+ }
+ }
+
+//YourPage.xaml.cs
+using System.Collections.Generic;
+using Microsoft.UI.Xaml.Controls;
+
+namespace YourNamespace;
+
+public sealed partial class YourPage : Page
+{
+ public YourPage()
+ {
+ this.InitializeComponent();
+
+ // Example synonyms dictionary
+ var synonymsDictionary = new Dictionary>
+ {
+ { "happy", new List { "joyful", "cheerful", "content" } },
+ { "fast", new List { "quick", "speedy", "rapid" } },
+ { "smart", new List { "intelligent", "clever", "bright" } }
+ };
+
+ // Set data source
+ SynonymFinder.SynonymsSource = synonymsDictionary;
+ }
+}
\ No newline at end of file
diff --git a/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample4_xaml.txt b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample4_xaml.txt
new file mode 100644
index 000000000..5f0940561
--- /dev/null
+++ b/WinUIGallery/Samples/SampleCode/CustomUserControls/CustomUserControlsSample4_xaml.txt
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WinUIGallery/WinUIGallery.csproj b/WinUIGallery/WinUIGallery.csproj
index 13a560571..4ecba44d8 100644
--- a/WinUIGallery/WinUIGallery.csproj
+++ b/WinUIGallery/WinUIGallery.csproj
@@ -295,6 +295,9 @@
+
+
+
@@ -457,6 +460,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+
+
+
+
+
+ MSBuild:Compile
+
+
+
+
+
+ MSBuild:Compile
+