diff --git a/components/Segmented/OpenSolution.bat b/components/Segmented/OpenSolution.bat
new file mode 100644
index 00000000..814a56d4
--- /dev/null
+++ b/components/Segmented/OpenSolution.bat
@@ -0,0 +1,3 @@
+@ECHO OFF
+
+powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*
\ No newline at end of file
diff --git a/components/Segmented/samples/Assets/Segmented.png b/components/Segmented/samples/Assets/Segmented.png
new file mode 100644
index 00000000..ba9ad789
Binary files /dev/null and b/components/Segmented/samples/Assets/Segmented.png differ
diff --git a/components/Segmented/samples/Dependencies.props b/components/Segmented/samples/Dependencies.props
new file mode 100644
index 00000000..e622e1df
--- /dev/null
+++ b/components/Segmented/samples/Dependencies.props
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Segmented/samples/Segmented.Samples.csproj b/components/Segmented/samples/Segmented.Samples.csproj
new file mode 100644
index 00000000..bb7b1ed2
--- /dev/null
+++ b/components/Segmented/samples/Segmented.Samples.csproj
@@ -0,0 +1,8 @@
+
+
+ Segmented
+
+
+
+
+
diff --git a/components/Segmented/samples/Segmented.md b/components/Segmented/samples/Segmented.md
new file mode 100644
index 00000000..39afa292
--- /dev/null
+++ b/components/Segmented/samples/Segmented.md
@@ -0,0 +1,28 @@
+---
+title: Segmented
+author: niels9001
+description: A common UI control to configure a view or setting.
+keywords: SegmentedControl, Control, Layout, Segmented
+dev_langs:
+ - csharp
+category: Controls
+subcategory: Input
+discussion-id: 314
+issue-id: 392
+icon: Assets/Segmented.png
+---
+
+## The basics
+
+The `Segmented` control is best used with 2-5 items and does not support overflow. The `Icon` and `Content` property can be set on the `SegmentedItems`.
+
+> [!Sample SegmentedBasicSample]
+
+## Selection
+`Segmented` supports single and multi-selection. When `SelectionMode` is set to `Single` the first item will be selected by default. This can be overriden by settings `AutoSelection` to `false`.
+
+## Other styles
+
+The `Segmented` control contains various additional styles, to match the look and feel of your application. The `PivotSegmentedStyle` matches a modern `Pivot` style while the `ButtonSegmentedStyle` represents buttons.
+
+> [!SAMPLE SegmentedStylesSample]
diff --git a/components/Segmented/samples/SegmentedBasicSample.xaml b/components/Segmented/samples/SegmentedBasicSample.xaml
new file mode 100644
index 00000000..47d31e96
--- /dev/null
+++ b/components/Segmented/samples/SegmentedBasicSample.xaml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Segmented/samples/SegmentedBasicSample.xaml.cs b/components/Segmented/samples/SegmentedBasicSample.xaml.cs
new file mode 100644
index 00000000..9ebd0725
--- /dev/null
+++ b/components/Segmented/samples/SegmentedBasicSample.xaml.cs
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using CommunityToolkit.WinUI.Controls;
+
+namespace SegmentedExperiment.Samples;
+
+///
+/// An example sample page of a Segmented control.
+///
+[ToolkitSampleMultiChoiceOption("SelectionMode", "Single", "Multiple", Title = "Selection mode")]
+[ToolkitSampleMultiChoiceOption("Alignment", "Left", "Center", "Right", "Stretch", Title = "Horizontal alignment")]
+
+[ToolkitSample(id: nameof(SegmentedBasicSample), "Basics", description: $"A sample for showing how to create and use a {nameof(Segmented)} custom control.")]
+public sealed partial class SegmentedBasicSample : Page
+{
+ public SegmentedBasicSample()
+ {
+ this.InitializeComponent();
+ }
+
+ // TODO: See https://github.com/CommunityToolkit/Labs-Windows/issues/149
+ public static ListViewSelectionMode ConvertStringToSelectionMode(string selectionMode) => selectionMode switch
+ {
+ "Single" => ListViewSelectionMode.Single,
+ "Multiple" => ListViewSelectionMode.Multiple,
+ _ => throw new System.NotImplementedException(),
+ };
+
+ public static HorizontalAlignment ConvertStringToHorizontalAlignment(string alignment) => alignment switch
+ {
+ "Left" => HorizontalAlignment.Left,
+ "Center" => HorizontalAlignment.Center,
+ "Right" => HorizontalAlignment.Right,
+ "Stretch" => HorizontalAlignment.Stretch,
+ _ => throw new System.NotImplementedException(),
+ };
+}
+
diff --git a/components/Segmented/samples/SegmentedStylesSample.xaml b/components/Segmented/samples/SegmentedStylesSample.xaml
new file mode 100644
index 00000000..511c7eb2
--- /dev/null
+++ b/components/Segmented/samples/SegmentedStylesSample.xaml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Item 1
+ Item 2
+ Item with long label
+ Item 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Segmented/samples/SegmentedStylesSample.xaml.cs b/components/Segmented/samples/SegmentedStylesSample.xaml.cs
new file mode 100644
index 00000000..f3fac18d
--- /dev/null
+++ b/components/Segmented/samples/SegmentedStylesSample.xaml.cs
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace SegmentedExperiment.Samples;
+
+///
+/// An sample that shows how the Segmented control has multiple built-in styles.
+///
+[ToolkitSampleMultiChoiceOption("SelectionMode", "Single", "Multiple", Title = "Selection mode")]
+
+[ToolkitSample(id: nameof(SegmentedStylesSample), "Additional styles", description: "A sample on how to use different built-in styles.")]
+public sealed partial class SegmentedStylesSample : Page
+{
+ public SegmentedStylesSample()
+ {
+ this.InitializeComponent();
+ }
+ public static ListViewSelectionMode ConvertStringToSelectionMode(string selectionMode) => selectionMode switch
+ {
+ "Single" => ListViewSelectionMode.Single,
+ "Multiple" => ListViewSelectionMode.Multiple,
+ _ => throw new System.NotImplementedException(),
+ };
+}
diff --git a/components/Segmented/src/CommunityToolkit.WinUI.Controls.Segmented.csproj b/components/Segmented/src/CommunityToolkit.WinUI.Controls.Segmented.csproj
new file mode 100644
index 00000000..5cc12018
--- /dev/null
+++ b/components/Segmented/src/CommunityToolkit.WinUI.Controls.Segmented.csproj
@@ -0,0 +1,20 @@
+
+
+ Segmented
+ This package contains Segmented.
+
+
+ CommunityToolkit.WinUI.Controls.SegmentedRns
+
+
+
+
+
+
+
+
+
+
+ $(PackageIdPrefix).$(PackageIdVariant).Controls.$(ToolkitComponentName)
+
+
diff --git a/components/Segmented/src/Dependencies.props b/components/Segmented/src/Dependencies.props
new file mode 100644
index 00000000..e622e1df
--- /dev/null
+++ b/components/Segmented/src/Dependencies.props
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/Segmented/src/EqualPanel.cs b/components/Segmented/src/EqualPanel.cs
new file mode 100644
index 00000000..9e2eb548
--- /dev/null
+++ b/components/Segmented/src/EqualPanel.cs
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Data;
+
+namespace CommunityToolkit.WinUI.Controls;
+
+public partial class EqualPanel : Panel
+{
+ private double _maxItemWidth = 0;
+ private double _maxItemHeight = 0;
+ private int _visibleItemsCount = 0;
+ public double Spacing
+ {
+ get { return (double)GetValue(SpacingProperty); }
+ set { SetValue(SpacingProperty, value); }
+ }
+
+ ///
+ /// Identifies the Spacing dependency property.
+ ///
+ /// The identifier for the dependency property.
+ public static readonly DependencyProperty SpacingProperty = DependencyProperty.Register(
+ nameof(Spacing),
+ typeof(double),
+ typeof(EqualPanel),
+ new PropertyMetadata(default(double), OnSpacingChanged));
+
+ public EqualPanel()
+ {
+ RegisterPropertyChangedCallback(HorizontalAlignmentProperty, OnHorizontalAlignmentChanged);
+ }
+
+ protected override Size MeasureOverride(Size availableSize)
+ {
+ _maxItemWidth = 0;
+ _maxItemHeight = 0;
+
+ var elements = Children.Where(static e => e.Visibility == Visibility.Visible);
+ _visibleItemsCount = elements.Count();
+
+ foreach (var child in elements)
+ {
+ child.Measure(availableSize);
+ _maxItemWidth = Math.Max(_maxItemWidth, child.DesiredSize.Width);
+ _maxItemHeight = Math.Max(_maxItemHeight, child.DesiredSize.Height);
+ }
+
+ if (_visibleItemsCount > 0)
+ {
+ // Return equal widths based on the widest item
+ // In very specific edge cases the AvailableWidth might be infinite resulting in a crash.
+ if (HorizontalAlignment != HorizontalAlignment.Stretch || double.IsInfinity(availableSize.Width))
+ {
+ return new Size((_maxItemWidth * _visibleItemsCount) + (Spacing * (_visibleItemsCount - 1)), _maxItemHeight);
+ }
+ else
+ {
+ // Equal columns based on the available width, adjust for spacing
+ double totalWidth = availableSize.Width - (Spacing * (_visibleItemsCount - 1));
+ _maxItemWidth = totalWidth / _visibleItemsCount;
+ return new Size(availableSize.Width, _maxItemHeight);
+ }
+ }
+ else
+ {
+ return new Size(0, 0);
+ }
+ }
+
+ protected override Size ArrangeOverride(Size finalSize)
+ {
+ double x = 0;
+
+ // Check if there's more width available - if so, recalculate (e.g. whenever Grid.Column is set to Auto)
+ if (finalSize.Width > _visibleItemsCount * _maxItemWidth + (Spacing * (_visibleItemsCount - 1)))
+ {
+ MeasureOverride(finalSize);
+ }
+
+ var elements = Children.Where(static e => e.Visibility == Visibility.Visible);
+ foreach (var child in elements)
+ {
+ child.Arrange(new Rect(x, 0, _maxItemWidth, _maxItemHeight));
+ x += _maxItemWidth + Spacing;
+ }
+ return finalSize;
+ }
+
+ private void OnHorizontalAlignmentChanged(DependencyObject sender, DependencyProperty dp)
+ {
+ InvalidateMeasure();
+ }
+
+ private static void OnSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var panel = (EqualPanel)d;
+ panel.InvalidateMeasure();
+ }
+}
diff --git a/components/Segmented/src/Helpers/ControlHelpers.cs b/components/Segmented/src/Helpers/ControlHelpers.cs
new file mode 100644
index 00000000..28c3c8af
--- /dev/null
+++ b/components/Segmented/src/Helpers/ControlHelpers.cs
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace CommunityToolkit.WinUI.Controls;
+
+internal static partial class ControlHelpers
+{
+ internal static bool IsXamlRootAvailable { get; } = Windows.Foundation.Metadata.ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "XamlRoot");
+}
diff --git a/components/Segmented/src/Helpers/SegmentedMarginConverter.cs b/components/Segmented/src/Helpers/SegmentedMarginConverter.cs
new file mode 100644
index 00000000..9de95ded
--- /dev/null
+++ b/components/Segmented/src/Helpers/SegmentedMarginConverter.cs
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace CommunityToolkit.WinUI.Controls;
+
+public partial class SegmentedMarginConverter : DependencyObject, IValueConverter
+{
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty LeftItemMarginProperty =
+ DependencyProperty.Register(nameof(LeftItemMargin), typeof(Thickness), typeof(SegmentedMarginConverter), new PropertyMetadata(null));
+
+ ///
+ /// Gets or sets the margin of the first item
+ ///
+ public Thickness LeftItemMargin
+ {
+ get { return (Thickness)GetValue(LeftItemMarginProperty); }
+ set { SetValue(LeftItemMarginProperty, value); }
+ }
+
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty MiddleItemMarginProperty =
+ DependencyProperty.Register(nameof(MiddleItemMargin), typeof(Thickness), typeof(SegmentedMarginConverter), new PropertyMetadata(null));
+
+ ///
+ /// Gets or sets the margin of any middle item
+ ///
+ public Thickness MiddleItemMargin
+ {
+ get { return (Thickness)GetValue(MiddleItemMarginProperty); }
+ set { SetValue(MiddleItemMarginProperty, value); }
+ }
+
+ ///
+ /// Identifies the property.
+ ///
+ public static readonly DependencyProperty RightItemMarginProperty =
+ DependencyProperty.Register(nameof(RightItemMargin), typeof(Thickness), typeof(SegmentedMarginConverter), new PropertyMetadata(null));
+
+ ///
+ /// Gets or sets the margin of the last item
+ ///
+ public Thickness RightItemMargin
+ {
+ get { return (Thickness)GetValue(RightItemMarginProperty); }
+ set { SetValue(RightItemMarginProperty, value); }
+ }
+
+ public object Convert(object value, Type targetType, object parameter, string language)
+ {
+ var segmentedItem = value as SegmentedItem;
+ var listView = ItemsControl.ItemsControlFromItemContainer(segmentedItem);
+
+ int index = listView.IndexFromContainer(segmentedItem);
+
+ if (index == 0)
+ {
+ return LeftItemMargin;
+ }
+ else if (index == listView.Items.Count - 1)
+ {
+ return RightItemMargin;
+ }
+ else
+ {
+ return MiddleItemMargin;
+ }
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ return value;
+ }
+}
diff --git a/components/Segmented/src/MultiTarget.props b/components/Segmented/src/MultiTarget.props
new file mode 100644
index 00000000..b11c1942
--- /dev/null
+++ b/components/Segmented/src/MultiTarget.props
@@ -0,0 +1,9 @@
+
+
+
+ uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android;
+
+
\ No newline at end of file
diff --git a/components/Segmented/src/Segmented/Segmented.cs b/components/Segmented/src/Segmented/Segmented.cs
new file mode 100644
index 00000000..75e0fb0f
--- /dev/null
+++ b/components/Segmented/src/Segmented/Segmented.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Windows.System;
+
+namespace CommunityToolkit.WinUI.Controls;
+
+public partial class Segmented : ListViewBase
+{
+ private int _internalSelectedIndex = -1;
+ private bool _hasLoaded = false;
+
+ public Segmented()
+ {
+ this.DefaultStyleKey = typeof(Segmented);
+
+ RegisterPropertyChangedCallback(SelectedIndexProperty, OnSelectedIndexChanged);
+ }
+
+ protected override DependencyObject GetContainerForItemOverride() => new SegmentedItem();
+
+ protected override bool IsItemItsOwnContainerOverride(object item)
+ {
+ return item is SegmentedItem;
+ }
+
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ if (!_hasLoaded)
+ {
+ SelectedIndex = _internalSelectedIndex;
+ _hasLoaded = true;
+ }
+ PreviewKeyDown -= Segmented_PreviewKeyDown;
+ PreviewKeyDown += Segmented_PreviewKeyDown;
+ }
+
+ protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
+ {
+ base.PrepareContainerForItemOverride(element, item);
+ if (element is SegmentedItem segmentedItem)
+ {
+ segmentedItem.Loaded += SegmentedItem_Loaded;
+ }
+ }
+
+ private void Segmented_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
+ {
+ switch (e.Key)
+ {
+ case VirtualKey.Left: e.Handled = MoveFocus(MoveDirection.Previous); break;
+ case VirtualKey.Right: e.Handled = MoveFocus(MoveDirection.Next); break;
+ }
+ }
+
+ private void SegmentedItem_Loaded(object sender, RoutedEventArgs e)
+ {
+ if (sender is SegmentedItem segmentedItem)
+ {
+ segmentedItem.Loaded -= SegmentedItem_Loaded;
+ }
+ }
+
+ protected override void OnItemsChanged(object e)
+ {
+ base.OnItemsChanged(e);
+ }
+
+ private enum MoveDirection
+ {
+ Next,
+ Previous
+ }
+
+ ///
+ /// Adjust the selected item and range based on keyboard input.
+ /// This is used to override the ListView behaviors for up/down arrow manipulation vs left/right for a horizontal control
+ ///
+ /// direction to move the selection
+ /// True if the focus was moved, false otherwise
+ private bool MoveFocus(MoveDirection direction)
+ {
+ bool retVal = false;
+ var currentContainerItem = GetCurrentContainerItem();
+
+ if (currentContainerItem != null)
+ {
+ var currentItem = ItemFromContainer(currentContainerItem);
+ var previousIndex = Items.IndexOf(currentItem);
+ var index = previousIndex;
+
+ if (direction == MoveDirection.Previous)
+ {
+ if (previousIndex > 0)
+ {
+ index -= 1;
+ }
+ else
+ {
+ retVal = true;
+ }
+ }
+ else if (direction == MoveDirection.Next)
+ {
+ if (previousIndex < Items.Count - 1)
+ {
+ index += 1;
+ }
+ }
+
+ // Only do stuff if the index is actually changing
+ if (index != previousIndex && ContainerFromIndex(index) is SegmentedItem newItem)
+ {
+ newItem.Focus(FocusState.Keyboard);
+ retVal = true;
+ }
+ }
+
+ return retVal;
+ }
+
+ private SegmentedItem? GetCurrentContainerItem()
+ {
+ if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
+ {
+ return FocusManager.GetFocusedElement(XamlRoot) as SegmentedItem;
+ }
+ else
+ {
+ return FocusManager.GetFocusedElement() as SegmentedItem;
+ }
+ }
+
+ private void OnSelectedIndexChanged(DependencyObject sender, DependencyProperty dp)
+ {
+ // This is a workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/8257
+ if (_internalSelectedIndex == -1 && SelectedIndex > -1)
+ {
+ // We catch the correct SelectedIndex and save it.
+ _internalSelectedIndex = SelectedIndex;
+ }
+ }
+}
diff --git a/components/Segmented/src/Segmented/Segmented.xaml b/components/Segmented/src/Segmented/Segmented.xaml
new file mode 100644
index 00000000..ffc5460b
--- /dev/null
+++ b/components/Segmented/src/Segmented/Segmented.xaml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+
+ 1
+ 2
+
+
+
+
+
+
+
+
+
diff --git a/components/Segmented/src/SegmentedItem/SegmentedItem.Properties.cs b/components/Segmented/src/SegmentedItem/SegmentedItem.Properties.cs
new file mode 100644
index 00000000..d7bf2824
--- /dev/null
+++ b/components/Segmented/src/SegmentedItem/SegmentedItem.Properties.cs
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace CommunityToolkit.WinUI.Controls;
+
+public partial class SegmentedItem : ListViewItem
+{
+ ///
+ /// The backing for the property.
+ ///
+ public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
+ nameof(Icon),
+ typeof(IconElement),
+ typeof(SegmentedItem),
+ new PropertyMetadata(defaultValue: null, (d, e) => ((SegmentedItem)d).OnIconPropertyChanged((IconElement)e.OldValue, (IconElement)e.NewValue)));
+
+ ///
+ /// Gets or sets the icon.
+ ///
+ public IconElement Icon
+ {
+ get => (IconElement)GetValue(IconProperty);
+ set => SetValue(IconProperty, value);
+ }
+}
diff --git a/components/Segmented/src/SegmentedItem/SegmentedItem.cs b/components/Segmented/src/SegmentedItem/SegmentedItem.cs
new file mode 100644
index 00000000..94a9769f
--- /dev/null
+++ b/components/Segmented/src/SegmentedItem/SegmentedItem.cs
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace CommunityToolkit.WinUI.Controls;
+
+[ContentProperty(Name = nameof(Content))]
+public partial class SegmentedItem : ListViewItem
+{
+ internal const string IconLeftState = "IconLeft";
+ internal const string IconOnlyState = "IconOnly";
+ internal const string ContentOnlyState = "ContentOnly";
+
+ public SegmentedItem()
+ {
+ this.DefaultStyleKey = typeof(SegmentedItem);
+ }
+
+ protected override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ OnIconChanged();
+ ContentChanged();
+ }
+
+ protected override void OnContentChanged(object oldContent, object newContent)
+ {
+ base.OnContentChanged(oldContent, newContent);
+ ContentChanged();
+ }
+
+ private void ContentChanged()
+ {
+ if (Content != null)
+ {
+ VisualStateManager.GoToState(this, IconLeftState, true);
+ }
+ else
+ {
+ VisualStateManager.GoToState(this, IconOnlyState, true);
+ }
+ }
+
+ protected virtual void OnIconPropertyChanged(IconElement oldValue, IconElement newValue)
+ {
+ OnIconChanged();
+ }
+
+ private void OnIconChanged()
+ {
+ if (Icon != null)
+ {
+ VisualStateManager.GoToState(this, IconLeftState, true);
+ }
+ else
+ {
+ VisualStateManager.GoToState(this, ContentOnlyState, true);
+ }
+ }
+}
diff --git a/components/Segmented/src/SegmentedItem/SegmentedItem.xaml b/components/Segmented/src/SegmentedItem/SegmentedItem.xaml
new file mode 100644
index 00000000..f4cfc4d5
--- /dev/null
+++ b/components/Segmented/src/SegmentedItem/SegmentedItem.xaml
@@ -0,0 +1,1098 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0.55
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0.55
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0.55
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 00:00:00.167
+
+
+
+
+
+ 3, 3, 1, 3
+ 1, 3, 1, 3
+ 1, 3, 3, 3
+ 11
+
+
+
+
+
+
+
diff --git a/components/Segmented/src/Themes/Generic.xaml b/components/Segmented/src/Themes/Generic.xaml
new file mode 100644
index 00000000..acf563f4
--- /dev/null
+++ b/components/Segmented/src/Themes/Generic.xaml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/components/Segmented/tests/ExampleSegmentedTestClass.cs b/components/Segmented/tests/ExampleSegmentedTestClass.cs
new file mode 100644
index 00000000..c2e040b9
--- /dev/null
+++ b/components/Segmented/tests/ExampleSegmentedTestClass.cs
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using CommunityToolkit.WinUI.Controls;
+using CommunityToolkit.Tooling.TestGen;
+using CommunityToolkit.Tests;
+
+namespace SegmentedExperiment.Tests;
+
+[TestClass]
+public partial class ExampleSegmentedTestClass : VisualUITestBase
+{
+ // If you don't need access to UI objects directly or async code, use this pattern.
+ [TestMethod]
+ public void SimpleSynchronousExampleTest()
+ {
+ var assembly = typeof(Segmented).Assembly;
+ var type = assembly.GetType(typeof(Segmented).FullName ?? string.Empty);
+
+ Assert.IsNotNull(type, "Could not find Segmented control type.");
+ Assert.AreEqual(typeof(Segmented), type, "Type of Segmented control does not match expected type.");
+ }
+
+ // If you don't need access to UI objects directly, use this pattern.
+ [TestMethod]
+ public async Task SimpleAsyncExampleTest()
+ {
+ await Task.Delay(250);
+
+ Assert.IsTrue(true);
+ }
+
+ // Example that shows how to check for exception throwing.
+ [TestMethod]
+ public void SimpleExceptionCheckTest()
+ {
+ // If you need to check exceptions occur for invalid inputs, etc...
+ // Use Assert.ThrowsException to limit the scope to where you expect the error to occur.
+ // Otherwise, using the ExpectedException attribute could swallow or
+ // catch other issues in setup code.
+ Assert.ThrowsException(() => throw new NotImplementedException());
+ }
+
+ // The UIThreadTestMethod automatically dispatches to the UI for us to work with UI objects.
+ [UIThreadTestMethod]
+ public void SimpleUIAttributeExampleTest()
+ {
+ var component = new Segmented();
+ Assert.IsNotNull(component);
+ }
+
+ // The UIThreadTestMethod can also easily grab a XAML Page for us by passing its type as a parameter.
+ // This lets us actually test a control as it would behave within an actual application.
+ // The page will already be loaded by the time your test is called.
+ [UIThreadTestMethod]
+ public void SimpleUIExamplePageTest(ExampleSegmentedTestPage page)
+ {
+ // You can use the Toolkit Visual Tree helpers here to find the component by type or name:
+ var component = page.FindDescendant();
+
+ Assert.IsNotNull(component);
+
+ var componentByName = page.FindDescendant("SegmentedControl");
+
+ Assert.IsNotNull(componentByName);
+ }
+
+ // You can still do async work with a UIThreadTestMethod as well.
+ [UIThreadTestMethod]
+ public async Task SimpleAsyncUIExamplePageTest(ExampleSegmentedTestPage page)
+ {
+ // This helper can be used to wait for a rendering pass to complete.
+ await CompositionTargetHelper.ExecuteAfterCompositionRenderingAsync(() => { });
+
+ var component = page.FindDescendant();
+
+ Assert.IsNotNull(component);
+ }
+
+ //// ----------------------------- ADVANCED TEST SCENARIOS -----------------------------
+
+ // If you need to use DataRow, you can use this pattern with the UI dispatch still.
+ // Otherwise, checkout the UIThreadTestMethod attribute above.
+ // See https://github.com/CommunityToolkit/Labs-Windows/issues/186
+ [TestMethod]
+ public async Task ComplexAsyncUIExampleTest()
+ {
+ await EnqueueAsync(() =>
+ {
+ var component = new Segmented();
+ Assert.IsNotNull(component);
+ });
+ }
+
+ // If you want to load other content not within a XAML page using the UIThreadTestMethod above.
+ // Then you can do that using the Load/UnloadTestContentAsync methods.
+ [TestMethod]
+ public async Task ComplexAsyncLoadUIExampleTest()
+ {
+ await EnqueueAsync(async () =>
+ {
+ var component = new Segmented();
+ Assert.IsNotNull(component);
+ Assert.IsFalse(component.IsLoaded);
+
+ await LoadTestContentAsync(component);
+
+ Assert.IsTrue(component.IsLoaded);
+
+ await UnloadTestContentAsync(component);
+
+ Assert.IsFalse(component.IsLoaded);
+ });
+ }
+
+ // You can still use the UIThreadTestMethod to remove the extra layer for the dispatcher as well:
+ [UIThreadTestMethod]
+ public async Task ComplexAsyncLoadUIExampleWithoutDispatcherTest()
+ {
+ var component = new Segmented();
+ Assert.IsNotNull(component);
+ Assert.IsFalse(component.IsLoaded);
+
+ await LoadTestContentAsync(component);
+
+ Assert.IsTrue(component.IsLoaded);
+
+ await UnloadTestContentAsync(component);
+
+ Assert.IsFalse(component.IsLoaded);
+ }
+}
diff --git a/components/Segmented/tests/ExampleSegmentedTestPage.xaml b/components/Segmented/tests/ExampleSegmentedTestPage.xaml
new file mode 100644
index 00000000..3223a11a
--- /dev/null
+++ b/components/Segmented/tests/ExampleSegmentedTestPage.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
diff --git a/components/Segmented/tests/ExampleSegmentedTestPage.xaml.cs b/components/Segmented/tests/ExampleSegmentedTestPage.xaml.cs
new file mode 100644
index 00000000..23376e02
--- /dev/null
+++ b/components/Segmented/tests/ExampleSegmentedTestPage.xaml.cs
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace SegmentedExperiment.Tests;
+
+///
+/// An empty page that can be used on its own or navigated to within a Frame.
+///
+public sealed partial class ExampleSegmentedTestPage : Page
+{
+ public ExampleSegmentedTestPage()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/components/Segmented/tests/Segmented.Tests.projitems b/components/Segmented/tests/Segmented.Tests.projitems
new file mode 100644
index 00000000..9c0e88b3
--- /dev/null
+++ b/components/Segmented/tests/Segmented.Tests.projitems
@@ -0,0 +1,23 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ AA9FB2D1-9A19-4442-A2FC-B62003F99558
+
+
+ SegmentedExperiment.Tests
+
+
+
+
+ ExampleSegmentedTestPage.xaml
+
+
+
+
+ Designer
+ MSBuild:Compile
+
+
+
\ No newline at end of file
diff --git a/components/Segmented/tests/Segmented.Tests.shproj b/components/Segmented/tests/Segmented.Tests.shproj
new file mode 100644
index 00000000..9c2cfd0e
--- /dev/null
+++ b/components/Segmented/tests/Segmented.Tests.shproj
@@ -0,0 +1,13 @@
+
+
+
+ AA9FB2D1-9A19-4442-A2FC-B62003F99558
+ 14.0
+
+
+
+
+
+
+
+