Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Porting TokenizingTextBox #77

Merged
merged 30 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5e7fd1c
Init
niels9001 Jun 1, 2023
c3f1cea
Fixing namespaces
niels9001 Jun 1, 2023
f80f185
resolving platform diferences
niels9001 Jun 1, 2023
4c7e25b
Fix ref
niels9001 Jun 1, 2023
36325e6
Working sample
niels9001 Jun 1, 2023
6b80aa8
Update TokenizingTextBoxCustomSample.xaml
niels9001 Jun 1, 2023
de0c74e
Design fixes
niels9001 Jun 3, 2023
c5f1572
Visual updates
niels9001 Jun 3, 2023
4eeaa2c
Merge branch 'main' into niels9001/TokenizingTextBox
niels9001 Jun 3, 2023
cafa1a3
Update tooling
niels9001 Jun 3, 2023
44d9bd9
More changes
niels9001 Jun 5, 2023
f156c4e
Updating samples and tests
niels9001 Jun 5, 2023
c3e2613
Adding SampleEmailType
niels9001 Jun 6, 2023
80f35ee
Remove unused files
niels9001 Jun 6, 2023
eb1adbe
Sample improvements
niels9001 Jun 6, 2023
605d9f0
Uno improvements
niels9001 Jun 7, 2023
f982bca
Remove local WrapPanel
niels9001 Jun 7, 2023
e0bf8a9
Merge branch 'main' into niels9001/TokenizingTextBox
niels9001 Jun 7, 2023
bf51fc6
Revert "Remove local WrapPanel"
niels9001 Jun 7, 2023
48e34dd
Fix test
niels9001 Jun 7, 2023
ecabf8e
Remove local WrapPanel
niels9001 Jun 7, 2023
d56e2cd
Remove unused code from sample
niels9001 Jun 7, 2023
e299336
Merge branch 'main' into niels9001/TokenizingTextBox
niels9001 Jun 21, 2023
a83ca38
Merge branch 'main' into niels9001/TokenizingTextBox
niels9001 Jun 21, 2023
7937930
Adding icons
niels9001 Jun 21, 2023
3245135
Update components/TokenizingTextBox/src/CommunityToolkit.WinUI.Contro…
Arlodotexe Jun 21, 2023
34e8ab6
Update components/TokenizingTextBox/src/InterspersedObservableCollect…
niels9001 Jul 6, 2023
fdfcb90
Removed extraneous information from TokenizingTextBox sample docs
Arlodotexe Jul 10, 2023
f60895c
Get dispatcher queue from constructor
Arlodotexe Jul 11, 2023
71608d9
Merge branch 'main' into niels9001/TokenizingTextBox
Arlodotexe Jul 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ToolkitEffectSourceProject>$(RepositoryDirectory)\components\Effects\src\CommunityToolkit.WinUI.Effects.csproj</ToolkitEffectSourceProject>
<ToolkitBehaviorSourceProject>$(RepositoryDirectory)\components\Behaviors\src\CommunityToolkit.WinUI.Behaviors.csproj</ToolkitBehaviorSourceProject>
<ToolkitAnimationSourceProject>$(RepositoryDirectory)\components\Animations\src\CommunityToolkit.WinUI.Animations.csproj</ToolkitAnimationSourceProject>
<ToolkitPrimitiveSourceProject>$(RepositoryDirectory)\components\Primitives\src\CommunityToolkit.WinUI.Controls.Primitives.csproj</ToolkitPrimitiveSourceProject>
</PropertyGroup>

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
Expand Down
3 changes: 3 additions & 0 deletions components/TokenizingTextBox/OpenSolution.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@ECHO OFF

powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions components/TokenizingTextBox/samples/Dependencies.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>

<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>
26 changes: 26 additions & 0 deletions components/TokenizingTextBox/samples/SampleDataType.cs
Original file line number Diff line number Diff line change
@@ -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 TokenizingTextBoxExperiment.Samples;

/// <summary>
/// Sample of strongly-typed data for <see cref="CommunityToolkit.WinUI.Controls.TokenizingTextBox"/>.
/// </summary>
public class SampleDataType
{
/// <summary>
/// Gets or sets symbol to display.
/// </summary>
public Symbol Icon { get; set; }

/// <summary>
/// Gets or sets text to display.
/// </summary>
public string? Text { get; set; }

public override string ToString()
{
return Text!;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>TokenizingTextBox</ToolkitComponentName>
</PropertyGroup>

<!-- Sets this up as a toolkit component's sample project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
</Project>
71 changes: 71 additions & 0 deletions components/TokenizingTextBox/samples/TokenizingTextBox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
title: TokenizingTextBox
author: michael-hawker
description: A text input control that auto-suggests and displays token items.
keywords: TokenizingTextBox, control, tokens
dev_langs:
- csharp
category: Controls
subcategory: Input
discussion-id: 0
issue-id: 0
icon: Assets/TokenizingTextBox.png
---

# TokenizingTextBox

The [TokenizingTextBox](/dotnet/api/microsoft.toolkit.uwp.ui.controls.tokenizingtextbox) is an advanced [AutoSuggestBox](/uwp/api/Windows.UI.Xaml.Controls.AutoSuggestBox) which will display selected items as tokens within the textbox. A user can easily see the picked items or remove them easily.

> [!Sample TokenizingTextBoxSample]

## Syntax

```xaml
<controls:TokenizingTextBox
QueryIcon="Tag"
PlaceholderText="Add tags"
TokenDelimiter=","/>
```

## Properties

| Property | Type | Description |
| -- | -- | -- |
| AutoSuggestBoxStyle | Style | Inner AutoSuggestBox style |
| AutoSuggestBoxTextBoxStyle | Style | Inner TextBox style of the AutoSuggestBox |
| PlaceholderText | string | Placeholder text to display when there's no text in the textbox |
| QueryIcon | IconSource |
| QueryText | string | Gets or sets the text query of the AutoSuggestBox |
| SelectedItems | IList&lt;object&gt; | Collection of items selected by the user |
| SelectedTokenText | string | Complete set of text for any selection in the control |
| SuggestedItemsSource | object | List of suggested items |
| SuggestedItemTemplate | DataTemplate | Template for suggested items |
| SuggestedItemTemplateSelector | DataTemplateSelector | Template selector for suggested items |
| SuggestedItemContainerStyle | Style for suggested item's container |
| TabNavigateBackOnArrow | bool | Value indicating whether the control will move focus to the previous control when an arrow key is pressed and selection is at one of the limits in the control. |
| Text | string | Text of currently focused text box part |
| TextMemberPath | string | Path of property for item display |
| TokenDelimiter | string | Character delimiter for recognizing a token |
| TokenItemTemplate | DataTemplate | Template for a token item |
| TokenItemTemplateSelector | DataTemplateSelector | Template selector for token items |
| TokenItemStyle | Style | Style for a token item |
| TokenSpacing | double | Amount of spacing between tokens |

## Methods

| Methods | Return Type | Description |
| -- | -- | -- |
| AddTokenItem(data, bool) | void | Used in special cases where you want to add a token manually to the control |
| ClearAsync() | Task | Clears everything from the control, tokens and text. |
| GetUntokenizedText(string) | string | Returns the string representation of each token item, concatenated and delimited. |

## Events

| Events | Description |
| -- | -- |
| QuerySubmitted | Event raised when the user submits the text query. |
| SuggestionChosen | Event raised when a suggested item is chosen by the user. |
| TextChanged | Event raised when the text input value has changed. |
| TokenItemAdding | Event raised before a new token item has been added. Can be used to transform user text into an object. |
| TokenItemRemoving | Event raised before a token item is removed (cancelable). |
| TokenItemRemoved | Event raised after a token item has been removed. |
Arlodotexe marked this conversation as resolved.
Show resolved Hide resolved
83 changes: 83 additions & 0 deletions components/TokenizingTextBox/samples/TokenizingTextBoxSample.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!-- 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. -->
<Page x:Class="TokenizingTextBoxExperiment.Samples.TokenizingTextBoxSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:TokenizingTextBoxExperiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="using:CommunityToolkit.WinUI"
mc:Ignorable="d">

<StackPanel Orientation="Vertical"
Spacing="4">
<controls:TokenizingTextBox x:Name="TokenBox"
MaxWidth="620"
HorizontalAlignment="Left"
ItemClick="TokenBox_ItemClick"
ItemsSource="{x:Bind SelectedTokens, Mode=TwoWay}"
Loaded="TokenBox_Loaded"
MaximumTokens="5"
PlaceholderText="Add actions"
QueryIcon="{ui:FontIconSource Glyph=&#xE721;,
FontSize=12}"
SuggestedItemsSource="{x:Bind _samples, Mode=OneWay}"
TextChanged="TextChanged"
TextMemberPath="Text"
TokenDelimiter=","
TokenItemAdding="TokenItemCreating">
<controls:TokenizingTextBox.Header>
<TextBlock>
<Run Text="Start typing and select up to" />
<Run FontWeight="SemiBold"
Text="{Binding MaximumTokens, ElementName=TokenBox, Mode=OneWay}" />
<Run Text="actions" />
</TextBlock>
</controls:TokenizingTextBox.Header>
<controls:TokenizingTextBox.SuggestedItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Viewbox Width="16">
<SymbolIcon Symbol="{Binding Icon}" />
</Viewbox>
<TextBlock Padding="8,0,0,0"
Text="{Binding Text}" />
</StackPanel>
</DataTemplate>
</controls:TokenizingTextBox.SuggestedItemTemplate>
<controls:TokenizingTextBox.TokenItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Viewbox Width="16">
<SymbolIcon Symbol="{Binding Icon}" />
</Viewbox>

<TextBlock Padding="8,0,0,0"
Text="{Binding Text}" />
</StackPanel>
</DataTemplate>
</controls:TokenizingTextBox.TokenItemTemplate>
</controls:TokenizingTextBox>


<TextBlock Margin="0,24,0,0"
FontWeight="SemiBold"
Text="Text:" />
<TextBlock x:Name="currentEdit" />

<TextBlock Margin="0,24,0,0"
FontWeight="SemiBold"
Text="SelectedTokenText:" />
<TextBlock x:Name="selectedItemsString" />

<TextBlock Margin="0,24,0,0"
FontWeight="SemiBold"
Text="Items:" />
<ItemsControl ItemsSource="{x:Bind SelectedTokens, Mode=OneWay}" />

<TextBlock Margin="0,24,0,0"
FontWeight="SemiBold"
Text="Clicked item:" />
<TextBlock x:Name="clickedItem" />
</StackPanel>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// 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 TokenizingTextBoxExperiment.Samples;

[ToolkitSample(id: nameof(TokenizingTextBoxSample), "Basic sample", description: $"A sample for showing how to create and use a {nameof(TokenizingTextBox)}.")]
public sealed partial class TokenizingTextBoxSample : Page
{
public readonly List<SampleDataType> _samples = new List<SampleDataType>()
{
new SampleDataType() { Text = "Account", Icon = Symbol.Account },
new SampleDataType() { Text = "Add friend", Icon = Symbol.AddFriend },
new SampleDataType() { Text = "Attach", Icon = Symbol.Attach },
new SampleDataType() { Text = "Attach camera", Icon = Symbol.AttachCamera },
new SampleDataType() { Text = "Audio", Icon = Symbol.Audio },
new SampleDataType() { Text = "Block contact", Icon = Symbol.BlockContact },
new SampleDataType() { Text = "Calculator", Icon = Symbol.Calculator },
new SampleDataType() { Text = "Calendar", Icon = Symbol.Calendar },
new SampleDataType() { Text = "Camera", Icon = Symbol.Camera },
new SampleDataType() { Text = "Contact", Icon = Symbol.Contact },
new SampleDataType() { Text = "Favorite", Icon = Symbol.Favorite },
new SampleDataType() { Text = "Link", Icon = Symbol.Link },
new SampleDataType() { Text = "Mail", Icon = Symbol.Mail },
new SampleDataType() { Text = "Map", Icon = Symbol.Map },
new SampleDataType() { Text = "Phone", Icon = Symbol.Phone },
new SampleDataType() { Text = "Pin", Icon = Symbol.Pin },
new SampleDataType() { Text = "Rotate", Icon = Symbol.Rotate },
new SampleDataType() { Text = "Rotate camera", Icon = Symbol.RotateCamera },
new SampleDataType() { Text = "Send", Icon = Symbol.Send },
new SampleDataType() { Text = "Tags", Icon = Symbol.Tag },
new SampleDataType() { Text = "UnFavorite", Icon = Symbol.UnFavorite },
new SampleDataType() { Text = "UnPin", Icon = Symbol.UnPin },
new SampleDataType() { Text = "Zoom", Icon = Symbol.Zoom },
new SampleDataType() { Text = "ZoomIn", Icon = Symbol.ZoomIn },
new SampleDataType() { Text = "ZoomOut", Icon = Symbol.ZoomOut },
};

public ObservableCollection<SampleDataType> SelectedTokens { get; set; }

public TokenizingTextBoxSample()
{
this.InitializeComponent();
SelectedTokens = new()
{
_samples[0],
_samples[1]
};

}

private void TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
currentEdit.Text = TokenBox.Text;
SetSelectedTokenText();
}

private void SetSelectedTokenText()
{
selectedItemsString.Text = TokenBox.SelectedTokenText;
}

private void TokenItemCreating(object sender, TokenItemAddingEventArgs e)
{
// Take the user's text and convert it to our data type (if we have a matching one).
#if !HAS_UNO
e.Item = _samples.FirstOrDefault((item) => item.Text!.Contains(e.TokenText, StringComparison.CurrentCultureIgnoreCase));
#else
e.Item = _samples.FirstOrDefault((item) => item.Text!.Contains(e.TokenText));
#endif
// Otherwise, create a new version of our data type
if (e.Item == null)
{
e.Item = new SampleDataType()
{
Text = e.TokenText,
Icon = Symbol.OutlineStar
};
}
}

private void TokenBox_ItemClick(object sender, ItemClickEventArgs e)
{
if (e.ClickedItem is SampleDataType selectedItem)
{
clickedItem.Text = selectedItem.Text!;
}
}

private void TokenBox_Loaded(object sender, RoutedEventArgs e)
{
SetSelectedTokenText();
}
}
13 changes: 13 additions & 0 deletions components/TokenizingTextBox/src/AdditionalAssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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.Runtime.CompilerServices;

// These `InternalsVisibleTo` calls are intended to make it easier for
// for any internal code to be testable in all the different test projects
// used with the Labs infrastructure.
[assembly: InternalsVisibleTo("TokenizingTextBox.Tests.Uwp")]
[assembly: InternalsVisibleTo("TokenizingTextBox.Tests.WinAppSdk")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.Uwp")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.WinAppSdk")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>TokenizingTextBox</ToolkitComponentName>
<Description>This package contains TokenizingTextBox.</Description>
<Version>0.0.1</Version>

<!-- Rns suffix is required for namespaces shared across projects. See https://github.com/CommunityToolkit/Labs-Windows/issues/152 -->
<RootNamespace>CommunityToolkit.WinUI.Controls.TokenizingTextBoxRns</RootNamespace>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="$(ToolkitExtensionSourceProject)" />
<ProjectReference Include="$(ToolkitHelperSourceProject)" />
<ProjectReference Include="$(ToolkitPrimitiveSourceProject)" />
Arlodotexe marked this conversation as resolved.
Show resolved Hide resolved
</ItemGroup>

<!-- Sets this up as a toolkit component's source project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SourceProject.props" />
Arlodotexe marked this conversation as resolved.
Show resolved Hide resolved
</Project>
31 changes: 31 additions & 0 deletions components/TokenizingTextBox/src/Dependencies.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>

<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>
Loading