diff --git a/MADE-Uno.sln b/MADE-Uno.sln
index 2271bf0..fc44b96 100644
--- a/MADE-Uno.sln
+++ b/MADE-Uno.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.31624.102
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32126.317
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{01380FB8-F8A7-4416-AABA-5407574B7723}"
EndProject
@@ -39,6 +39,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MADE.UI.Styling", "src\MADE
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MADE.UI.ViewManagement", "src\MADE.UI.ViewManagement\MADE.UI.ViewManagement.csproj", "{442D1E25-FFD1-405D-A1FC-40CAFCAD190C}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MADE.UI.Controls.ChipBox", "src\MADE.UI.Controls.ChipBox\MADE.UI.Controls.ChipBox.csproj", "{D1A16208-5A34-4CC1-B175-01B5AC99E69E}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
samples\MADE.Samples\MADE.Samples.Shared\MADE.Samples.Shared.projitems*{04f1b32d-9056-43fc-b4c2-b8c5481bdacb}*SharedItemsImports = 4
@@ -799,6 +801,62 @@ Global
{442D1E25-FFD1-405D-A1FC-40CAFCAD190C}.Release|x64.Build.0 = Release|Any CPU
{442D1E25-FFD1-405D-A1FC-40CAFCAD190C}.Release|x86.ActiveCfg = Release|Any CPU
{442D1E25-FFD1-405D-A1FC-40CAFCAD190C}.Release|x86.Build.0 = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|ARM64.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|ARM64.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|ARM.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|ARM.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|ARM64.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|ARM64.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|x64.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|x64.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.AppStore|x86.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|ARM.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|ARM64.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|x64.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Debug|x86.Build.0 = Debug|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|ARM.ActiveCfg = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|ARM.Build.0 = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|ARM64.ActiveCfg = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|ARM64.Build.0 = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|iPhone.Build.0 = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|x64.ActiveCfg = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|x64.Build.0 = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|x86.ActiveCfg = Release|Any CPU
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -819,6 +877,7 @@ Global
{0CA60466-059C-42D3-9B68-6BBB75A75090} = {01380FB8-F8A7-4416-AABA-5407574B7723}
{F8D00106-0598-45E7-B92E-EF408249C02E} = {01380FB8-F8A7-4416-AABA-5407574B7723}
{442D1E25-FFD1-405D-A1FC-40CAFCAD190C} = {01380FB8-F8A7-4416-AABA-5407574B7723}
+ {D1A16208-5A34-4CC1-B175-01B5AC99E69E} = {01380FB8-F8A7-4416-AABA-5407574B7723}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3921AD86-E6C0-4436-8880-2D9EDFAD6151}
diff --git a/README.md b/README.md
index 2c8313b..5dbb9cd 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ As many developers know, projects like MADE Uno are built and maintained in spar
| Package | Current | Preview | Downloads |
| ------ | ------ | ------ | ------ |
| UI | [](https://www.nuget.org/packages/MADE.UI/) | [](https://www.nuget.org/packages/MADE.UI/) | [](https://www.nuget.org/packages/MADE.UI) |
+| UI.Controls.ChipBox | [](https://www.nuget.org/packages/MADE.UI.Controls.ChipBox/) | [](https://www.nuget.org/packages/MADE.UI.Controls.ChipBox/) | [](https://www.nuget.org/packages/MADE.UI.Controls.ChipBox) |
| UI.Controls.DropDownList | [](https://www.nuget.org/packages/MADE.UI.Controls.DropDownList/) | [](https://www.nuget.org/packages/MADE.UI.Controls.DropDownList/) | [](https://www.nuget.org/packages/MADE.UI.Controls.DropDownList) |
| UI.Controls.FilePicker | [](https://www.nuget.org/packages/MADE.UI.Controls.FilePicker/) | [](https://www.nuget.org/packages/MADE.UI.Controls.FilePicker/) | [](https://www.nuget.org/packages/MADE.UI.Controls.FilePicker) |
| UI.Controls.Validator | [](https://www.nuget.org/packages/MADE.UI.Controls.Validator/) | [](https://www.nuget.org/packages/MADE.UI.Controls.Validator/) | [](https://www.nuget.org/packages/MADE.UI.Controls.Validator) |
diff --git a/assets/SampleIcons.afdesign b/assets/SampleIcons.afdesign
index ba3d264..601622e 100644
Binary files a/assets/SampleIcons.afdesign and b/assets/SampleIcons.afdesign differ
diff --git a/docs/articles/features/ui-controls-chipbox.md b/docs/articles/features/ui-controls-chipbox.md
new file mode 100644
index 0000000..518dd97
--- /dev/null
+++ b/docs/articles/features/ui-controls-chipbox.md
@@ -0,0 +1,132 @@
+---
+uid: package-ui-controls-chipbox
+title: Using the ChipBox control
+---
+
+# Using the ChipBox control
+
+The `MADE.UI.Controls.ChipBox` element is a custom-built UI element that works with [Uno's supported platforms](https://platform.uno/) that provides a multi value input for a text box with auto-suggest capabilities. Values added are displayed as removable chips.
+
+The control is a familiar custom input style control used in web applications.
+
+Shown below is the visuals for the control in its default state, with some chip values already added.
+
+
+
+## Example usage
+
+```xml
+
+
+
+
+
+
+```
+
+## Retrieving added chip values
+
+The control exposes the selected chips through the `Chips` list property.
+
+The type of objects contained in this collection will be `ChipItem` which contains the contents of the item as a generic `Object` type. This allows the `ChipBox` control to support any type of input value object.
+
+## Providing suggestions for chip values
+
+The `ChipBox` provides a `Suggestions` property that can be used to provide a list of objects that should be displayed to the user as suggestions.
+
+The control exposes a `TextChangeCommand` property and a `TextChanged` event that can be used to provide the ability to customize and provide relevant suggestions based on the text provided. This is not a baked in feature of the control itself. Here is an example of using this in action.
+
+```csharp
+private static readonly IList Places = new List
+{
+ "Austria",
+ "Belgium",
+ "Bulgaria",
+ "Croatia",
+ "Cyprus",
+ "Czechia",
+ "Denmark",
+ "Estonia",
+ "Finland",
+ "France",
+ "Germany",
+ "Greece",
+ "Hungary",
+ "Ireland",
+ "Italy",
+ "Latvia",
+ "Lithuania",
+ "Luxembourg",
+ "Malta",
+ "Netherlands",
+ "Poland",
+ "Portugal",
+ "Romania",
+ "Slovakia",
+ "Slovenia",
+ "Spain",
+ "Sweden"
+};
+
+public ICommand SuggestionTextChangeCommand => new RelayCommand(this.OnSuggestionTextChanged);
+
+public ObservableCollection ChipSuggestions { get; } = new(Places);
+
+private void OnSuggestionTextChanged(string obj)
+{
+ ChipSuggestions.MakeEqualTo(Places.Where(x => x.Contains(obj, StringComparison.CurrentCultureIgnoreCase)));
+}
+```
+
+It is up to the developer to implement the logic to provide suggestions. This is to ensure any flexibility in search and filtering is determined by the application rather than the control.
+
+## Customizing the ChipBox
+
+The control has many customization properties that are exposed to tailor the experience for your application.
+
+### HeaderTemplate
+
+The `Header` can be customized to include custom UI elements as well as a string resource.
+
+The `HeaderTemplate` is also available to provide a `DataTemplate` for you to define the rendered UI for the `Header`.
+
+### ChipContentTemplate
+
+The rendered UI elements for the chips use a MADE `Chip` content control. By default, the chips will be rendered displaying the string equivalent of the content provided to it. To customize the layout and display of the chip's content, apply a `DataTemplate` to the `ChipContentTemplate` property.
+
+### SuggestionsItemTemplate
+
+As suggestions could be a list of complex objects rather than a simple string, the control provides a `SuggestionsItemTemplate` property that can be used to provide a `DataTemplate` for the suggestions that are displayed to the user.
+
+### IsReadonly
+
+The `ChipBox` has the ability to be rendered in a readonly state. This is useful when you want to display the chips without any user interaction.
+
+When enabled, the auto-suggest text box will not be displayed to the user, and the ability to remove chips will be disabled.
+
+### AllowDuplicate
+
+By default, the `ChipBox` control allows duplicate values to be accepted. The `AllowDuplicate` property can be used to disable this behavior.
+
+### AllowFreeText
+
+The control supports the ability to allow free text input for chip values, as well as the option to only support selections from the suggestions list.
+
+The `AllowFreeText` property, enabled by default, can be used to control this behavior.
diff --git a/docs/articles/intro.md b/docs/articles/intro.md
index 94a4f1e..e311533 100644
--- a/docs/articles/intro.md
+++ b/docs/articles/intro.md
@@ -20,6 +20,7 @@ dotnet add package MADE.UI
| Package | Version |
| --- | --- |
| MADE.UI | [](https://www.nuget.org/packages/MADE.UI/) |
+| MADE.UI.Controls.ChipBox | [](https://www.nuget.org/packages/MADE.UI.Controls.ChipBox/) |
| MADE.UI.Controls.DropDownList | [](https://www.nuget.org/packages/MADE.UI.Controls.DropDownList/) |
| MADE.UI.Controls.FilePicker | [](https://www.nuget.org/packages/MADE.UI.Controls.FilePicker/) |
| MADE.UI.Controls.Validator | [](https://www.nuget.org/packages/MADE.UI.Controls.Validator/) |
@@ -42,6 +43,16 @@ Taking advantage of the Uno Platform, the UI packages provide extensible feature
+#### UI.Controls.ChipBox
+
+The UI Controls ChipBox library contains a cross-platform UI element that provides a multi value input for a text box with auto-suggest capabilities. Values added are displayed as removable chips.
+
+
+
+[Discover UI.Controls.ChipBox](features/ui-controls-chipbox.md)
+
+
+
#### UI.Controls.DropDownList
The UI Controls DropDownList library contains a Windows UI element that provides a selection user experience, allowing a user to select one or multiple items from a list.
diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml
index 693f7e1..b74f222 100644
--- a/docs/articles/toc.yml
+++ b/docs/articles/toc.yml
@@ -8,6 +8,8 @@
href: features/ui.md
- name: Controls
items:
+ - name: ChipBox
+ href: features/ui-controls-chipbox.md
- name: DropDownList
href: features/ui-controls-dropdownlist.md
- name: FilePicker
diff --git a/docs/images/ChipBox.png b/docs/images/ChipBox.png
new file mode 100644
index 0000000..e833c16
Binary files /dev/null and b/docs/images/ChipBox.png differ
diff --git a/samples/MADE.Samples/MADE.Samples.Droid/MADE.Samples.Droid.csproj b/samples/MADE.Samples/MADE.Samples.Droid/MADE.Samples.Droid.csproj
index a6f14fe..9fd02b6 100644
--- a/samples/MADE.Samples/MADE.Samples.Droid/MADE.Samples.Droid.csproj
+++ b/samples/MADE.Samples/MADE.Samples.Droid/MADE.Samples.Droid.csproj
@@ -78,10 +78,10 @@
2.1.0-uno.32
- 7.1.10
+ 7.1.11
-
-
+
+
@@ -107,6 +107,10 @@
+
+ {d1a16208-5a34-4cc1-b175-01b5ac99e69e}
+ MADE.UI.Controls.ChipBox
+ {774fd8d5-ccc1-4eed-aa14-f7069bfae5ce}MADE.UI.Controls.FilePicker
diff --git a/samples/MADE.Samples/MADE.Samples.Shared/Features/Home/ViewModels/MainPageViewModel.cs b/samples/MADE.Samples/MADE.Samples.Shared/Features/Home/ViewModels/MainPageViewModel.cs
index 9fe86c7..c8b24c3 100644
--- a/samples/MADE.Samples/MADE.Samples.Shared/Features/Home/ViewModels/MainPageViewModel.cs
+++ b/samples/MADE.Samples/MADE.Samples.Shared/Features/Home/ViewModels/MainPageViewModel.cs
@@ -32,6 +32,10 @@ private static ICollection GetSampleGroups()
Name = "Controls",
Samples =
{
+ new Sample(
+ "ChipBox",
+ typeof(ChipBoxPage),
+ "/Features/Samples/Assets/ChipBox/ChipBox.png"),
new Sample(
"FilePicker",
typeof(FilePickerPage),
diff --git a/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBox.png b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBox.png
new file mode 100644
index 0000000..cd74130
Binary files /dev/null and b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBox.png differ
diff --git a/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBoxCode.txt b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBoxCode.txt
new file mode 100644
index 0000000..df10381
--- /dev/null
+++ b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBoxCode.txt
@@ -0,0 +1,44 @@
+private static readonly IList Places = new List
+{
+ "Austria",
+ "Belgium",
+ "Bulgaria",
+ "Croatia",
+ "Cyprus",
+ "Czechia",
+ "Denmark",
+ "Estonia",
+ "Finland",
+ "France",
+ "Germany",
+ "Greece",
+ "Hungary",
+ "Ireland",
+ "Italy",
+ "Latvia",
+ "Lithuania",
+ "Luxembourg",
+ "Malta",
+ "Netherlands",
+ "Poland",
+ "Portugal",
+ "Romania",
+ "Slovakia",
+ "Slovenia",
+ "Spain",
+ "Sweden"
+};
+
+public ICommand SuggestionTextChangeCommand => new RelayCommand(this.OnSuggestionTextChanged);
+
+public ObservableCollection SelectedChips { get; } = new()
+{
+ new ChipItem("United Kingdom")
+};
+
+public ObservableCollection ChipSuggestions { get; } = new(Places);
+
+private void OnSuggestionTextChanged(string obj)
+{
+ ChipSuggestions.MakeEqualTo(Places.Where(x => x.Contains(obj, StringComparison.CurrentCultureIgnoreCase)));
+}
diff --git a/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBoxXaml.txt b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBoxXaml.txt
new file mode 100644
index 0000000..ad55d03
--- /dev/null
+++ b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Assets/ChipBox/ChipBoxXaml.txt
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Pages/ChipBoxPage.xaml b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Pages/ChipBoxPage.xaml
new file mode 100644
index 0000000..e12dd78
--- /dev/null
+++ b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Pages/ChipBoxPage.xaml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Pages/ChipBoxPage.xaml.cs b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Pages/ChipBoxPage.xaml.cs
new file mode 100644
index 0000000..59c4ad5
--- /dev/null
+++ b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/Pages/ChipBoxPage.xaml.cs
@@ -0,0 +1,21 @@
+namespace MADE.Samples.Features.Samples.Pages
+{
+ using CommunityToolkit.Mvvm.Messaging;
+ using MADE.Samples.Features.Samples.ViewModels;
+ using MADE.UI.Views.Navigation;
+ using MADE.UI.Views.Navigation.Pages;
+ using Microsoft.Extensions.DependencyInjection;
+
+ public sealed partial class ChipBoxPage : MvvmPage
+ {
+ public ChipBoxPage()
+ {
+ this.InitializeComponent();
+ this.DataContext = new ChipBoxPageViewModel(
+ App.Services.GetService(),
+ App.Services.GetService());
+ }
+
+ public ChipBoxPageViewModel ViewModel => this.DataContext as ChipBoxPageViewModel;
+ }
+}
diff --git a/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/ViewModels/ChipBoxPageViewModel.cs b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/ViewModels/ChipBoxPageViewModel.cs
new file mode 100644
index 0000000..e3768f0
--- /dev/null
+++ b/samples/MADE.Samples/MADE.Samples.Shared/Features/Samples/ViewModels/ChipBoxPageViewModel.cs
@@ -0,0 +1,74 @@
+namespace MADE.Samples.Features.Samples.ViewModels
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Linq;
+ using System.Windows.Input;
+ using CommunityToolkit.Mvvm.Input;
+ using CommunityToolkit.Mvvm.Messaging;
+ using MADE.Collections;
+ using MADE.UI.Controls;
+ using MADE.UI.Views.Navigation;
+ using MADE.UI.Views.Navigation.ViewModels;
+
+ public class ChipBoxPageViewModel : PageViewModel
+ {
+ private static readonly IList Places = new List
+ {
+ "Austria",
+ "Belgium",
+ "Bulgaria",
+ "Croatia",
+ "Cyprus",
+ "Czechia",
+ "Denmark",
+ "Estonia",
+ "Finland",
+ "France",
+ "Germany",
+ "Greece",
+ "Hungary",
+ "Ireland",
+ "Italy",
+ "Latvia",
+ "Lithuania",
+ "Luxembourg",
+ "Malta",
+ "Netherlands",
+ "Poland",
+ "Portugal",
+ "Romania",
+ "Slovakia",
+ "Slovenia",
+ "Spain",
+ "Sweden"
+ };
+
+ public ChipBoxPageViewModel(INavigationService navigationService, IMessenger messenger)
+ : base(navigationService, messenger)
+ {
+ }
+
+ public ICommand AddChipCommand => new RelayCommand(this.AddChip);
+
+ public ICommand SuggestionTextChangeCommand => new RelayCommand(this.OnSuggestionTextChanged);
+
+ public ObservableCollection SelectedChips { get; } = new()
+ {
+ new ChipItem("United Kingdom")
+ };
+
+ public ObservableCollection ChipSuggestions { get; } = new(Places);
+
+ private void OnSuggestionTextChanged(string obj)
+ {
+ ChipSuggestions.MakeEqualTo(Places.Where(x => x.Contains(obj, StringComparison.CurrentCultureIgnoreCase)));
+ }
+
+ private void AddChip()
+ {
+ this.SelectedChips.Add(new ChipItem("Global"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/MADE.Samples/MADE.Samples.Shared/MADE.Samples.Shared.projitems b/samples/MADE.Samples/MADE.Samples.Shared/MADE.Samples.Shared.projitems
index c31f181..d13f6b1 100644
--- a/samples/MADE.Samples/MADE.Samples.Shared/MADE.Samples.Shared.projitems
+++ b/samples/MADE.Samples/MADE.Samples.Shared/MADE.Samples.Shared.projitems
@@ -27,6 +27,9 @@
AppDialogPage.xaml
+
+ ChipBoxPage.xaml
+ FilePickerPage.xaml
@@ -37,6 +40,7 @@
WindowManagerPage.xaml
+
@@ -54,6 +58,17 @@
+
+
+ Designer
+
+
+
+
+ Designer
+
+
+ Designer
@@ -98,6 +113,10 @@
DesignerMSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+ DesignerMSBuild:Compile
diff --git a/samples/MADE.Samples/MADE.Samples.UWP/MADE.Samples.UWP.csproj b/samples/MADE.Samples/MADE.Samples.UWP/MADE.Samples.UWP.csproj
index 30a9837..ee6178e 100644
--- a/samples/MADE.Samples/MADE.Samples.UWP/MADE.Samples.UWP.csproj
+++ b/samples/MADE.Samples/MADE.Samples.UWP/MADE.Samples.UWP.csproj
@@ -41,8 +41,8 @@
MADE.Samplesen-USUAP
- 10.0.19041.0
- 10.0.17763.0
+ 10.0.22000.0
+ 10.0.19041.014512{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
@@ -143,6 +143,10 @@
+
+ {d1a16208-5a34-4cc1-b175-01b5ac99e69e}
+ MADE.UI.Controls.ChipBox
+ {347cdc37-e140-42fa-8710-a0f3297d2b6b}MADE.UI.Controls.DropDownList
diff --git a/samples/MADE.Samples/MADE.Samples.Wasm/MADE.Samples.Wasm.csproj b/samples/MADE.Samples/MADE.Samples.Wasm/MADE.Samples.Wasm.csproj
index e165854..58c7295 100644
--- a/samples/MADE.Samples/MADE.Samples.Wasm/MADE.Samples.Wasm.csproj
+++ b/samples/MADE.Samples/MADE.Samples.Wasm/MADE.Samples.Wasm.csproj
@@ -53,14 +53,15 @@
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/samples/MADE.Samples/MADE.Samples.iOS/MADE.Samples.iOS.csproj b/samples/MADE.Samples/MADE.Samples.iOS/MADE.Samples.iOS.csproj
index 1bce194..82d64d1 100644
--- a/samples/MADE.Samples/MADE.Samples.iOS/MADE.Samples.iOS.csproj
+++ b/samples/MADE.Samples/MADE.Samples.iOS/MADE.Samples.iOS.csproj
@@ -133,10 +133,10 @@
2.1.0-uno.32
- 7.1.10
+ 7.1.11
-
-
+
+
@@ -169,6 +169,10 @@
+
+ {d1a16208-5a34-4cc1-b175-01b5ac99e69e}
+ MADE.UI.Controls.ChipBox
+ {774fd8d5-ccc1-4eed-aa14-f7069bfae5ce}MADE.UI.Controls.FilePicker
diff --git a/src/MADE.UI.Controls.ChipBox/Chip.cs b/src/MADE.UI.Controls.ChipBox/Chip.cs
new file mode 100644
index 0000000..f891e42
--- /dev/null
+++ b/src/MADE.UI.Controls.ChipBox/Chip.cs
@@ -0,0 +1,118 @@
+// MADE Apps licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace MADE.UI.Controls
+{
+ using System.Windows.Input;
+ using MADE.UI.Extensions;
+ using Windows.UI.Xaml;
+ using Windows.UI.Xaml.Automation.Peers;
+ using Windows.UI.Xaml.Controls;
+
+ ///
+ /// Defines a control for displaying a value as a chip with remove capabilities.
+ ///
+ [TemplatePart(Name = ChipContentPart, Type = typeof(ContentPresenter))]
+ [TemplatePart(Name = ChipRemoveButtonPart, Type = typeof(Button))]
+ public sealed partial class Chip : ContentControl, IChip
+ {
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty RemoveCommandProperty = DependencyProperty.Register(
+ nameof(RemoveCommand),
+ typeof(ICommand),
+ typeof(Chip),
+ new PropertyMetadata(default(ICommand)));
+
+ ///
+ /// Identifies the dependency property.
+ ///
+ public static readonly DependencyProperty CanRemoveProperty = DependencyProperty.Register(
+ nameof(CanRemove),
+ typeof(bool),
+ typeof(Chip),
+ new PropertyMetadata(true, (o, args) => ((Chip)o).SetRemoveButtonVisibility()));
+
+ private const string ChipContentPart = "ChipContent";
+ private const string ChipRemoveButtonPart = "ChipRemoveButton";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Chip()
+ {
+ this.DefaultStyleKey = typeof(Chip);
+ }
+
+ ///
+ /// Occurs when the user pressed the remove chip button.
+ ///
+ public event ChipRemovedEventHandler Removed;
+
+ ///
+ /// Gets or sets the associated with when the user pressed the remove chip button.
+ ///
+ public ICommand RemoveCommand
+ {
+ get => (ICommand)GetValue(RemoveCommandProperty);
+ set => SetValue(RemoveCommandProperty, value);
+ }
+
+ ///
+ /// Gets or sets a value indicating whether the chip can be removed.
+ ///
+ public bool CanRemove
+ {
+ get => (bool)GetValue(CanRemoveProperty);
+ set => SetValue(CanRemoveProperty, value);
+ }
+
+ ///
+ /// Gets the view representing the remove chip button.
+ ///
+ public Button RemoveButton { get; private set; }
+
+ ///
+ /// Provides the class-specific implementation for the Microsoft UI Automation infrastructure.
+ ///
+ /// The class-specific instance.
+ protected override AutomationPeer OnCreateAutomationPeer()
+ {
+ return new ChipAutomationPeer(this);
+ }
+
+ ///
+ /// Loads the relevant control template so that it's parts can be referenced.
+ ///
+ protected override void OnApplyTemplate()
+ {
+ if (this.RemoveButton != null)
+ {
+ this.RemoveButton.Click -= this.OnRemoveClick;
+ }
+
+ base.OnApplyTemplate();
+
+ this.RemoveButton = this.GetChildView