Skip to content

Commit 56dff69

Browse files
niels9001Arlodotexemichael-hawker
authored
Porting TokenizingTextBox (#77)
* Init * Fixing namespaces * resolving platform diferences * Fix ref * Working sample * Update TokenizingTextBoxCustomSample.xaml * Design fixes * Visual updates * Update tooling * More changes * Updating samples and tests * Adding SampleEmailType * Remove unused files * Sample improvements * Uno improvements * Remove local WrapPanel * Revert "Remove local WrapPanel" This reverts commit f982bca. * Fix test * Remove local WrapPanel * Remove unused code from sample * Adding icons * Update components/TokenizingTextBox/src/CommunityToolkit.WinUI.Controls.TokenizingTextBox.csproj * Update components/TokenizingTextBox/src/InterspersedObservableCollection.cs Co-authored-by: Michael Hawker MSFT (XAML Llama) <[email protected]> * Removed extraneous information from TokenizingTextBox sample docs * Get dispatcher queue from constructor --------- Co-authored-by: Arlo <[email protected]> Co-authored-by: Michael Hawker MSFT (XAML Llama) <[email protected]>
1 parent bea1c71 commit 56dff69

34 files changed

+4700
-0
lines changed

Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<ToolkitEffectSourceProject>$(RepositoryDirectory)\components\Effects\src\CommunityToolkit.WinUI.Effects.csproj</ToolkitEffectSourceProject>
1010
<ToolkitBehaviorSourceProject>$(RepositoryDirectory)\components\Behaviors\src\CommunityToolkit.WinUI.Behaviors.csproj</ToolkitBehaviorSourceProject>
1111
<ToolkitAnimationSourceProject>$(RepositoryDirectory)\components\Animations\src\CommunityToolkit.WinUI.Animations.csproj</ToolkitAnimationSourceProject>
12+
<ToolkitPrimitiveSourceProject>$(RepositoryDirectory)\components\Primitives\src\CommunityToolkit.WinUI.Controls.Primitives.csproj</ToolkitPrimitiveSourceProject>
1213
</PropertyGroup>
1314

1415
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@ECHO OFF
2+
3+
powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*
2.15 KB
Loading
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<!--
2+
WinUI 2 under UWP uses TargetFramework uap10.0.*
3+
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
4+
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.
5+
6+
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.
7+
8+
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
9+
For UWP / WinAppSDK / Uno packages, place the package references here.
10+
-->
11+
<Project>
12+
<!-- WinUI 2 / UWP -->
13+
<ItemGroup Condition="'$(IsUwp)' == 'true'">
14+
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
15+
</ItemGroup>
16+
17+
<!-- WinUI 2 / Uno -->
18+
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
19+
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
20+
</ItemGroup>
21+
22+
<!-- WinUI 3 / WinAppSdk -->
23+
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
24+
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
25+
</ItemGroup>
26+
27+
<!-- WinUI 3 / Uno -->
28+
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
29+
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
30+
</ItemGroup>
31+
</Project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace TokenizingTextBoxExperiment.Samples;
6+
7+
/// <summary>
8+
/// Sample of strongly-typed data for <see cref="CommunityToolkit.WinUI.Controls.TokenizingTextBox"/>.
9+
/// </summary>
10+
public class SampleDataType
11+
{
12+
/// <summary>
13+
/// Gets or sets symbol to display.
14+
/// </summary>
15+
public Symbol Icon { get; set; }
16+
17+
/// <summary>
18+
/// Gets or sets text to display.
19+
/// </summary>
20+
public string? Text { get; set; }
21+
22+
public override string ToString()
23+
{
24+
return Text!;
25+
}
26+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
2+
<PropertyGroup>
3+
<ToolkitComponentName>TokenizingTextBox</ToolkitComponentName>
4+
</PropertyGroup>
5+
6+
<!-- Sets this up as a toolkit component's sample project -->
7+
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
8+
</Project>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
title: TokenizingTextBox
3+
author: michael-hawker
4+
description: A text input control that auto-suggests and displays token items.
5+
keywords: TokenizingTextBox, control, tokens
6+
dev_langs:
7+
- csharp
8+
category: Controls
9+
subcategory: Input
10+
discussion-id: 0
11+
issue-id: 0
12+
icon: Assets/TokenizingTextBox.png
13+
---
14+
15+
# TokenizingTextBox
16+
17+
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.
18+
19+
> [!Sample TokenizingTextBoxSample]
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<!-- 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. -->
2+
<Page x:Class="TokenizingTextBoxExperiment.Samples.TokenizingTextBoxSample"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:local="using:TokenizingTextBoxExperiment.Samples"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
xmlns:ui="using:CommunityToolkit.WinUI"
10+
mc:Ignorable="d">
11+
12+
<StackPanel Orientation="Vertical"
13+
Spacing="4">
14+
<controls:TokenizingTextBox x:Name="TokenBox"
15+
MaxWidth="620"
16+
HorizontalAlignment="Left"
17+
ItemClick="TokenBox_ItemClick"
18+
ItemsSource="{x:Bind SelectedTokens, Mode=TwoWay}"
19+
Loaded="TokenBox_Loaded"
20+
MaximumTokens="5"
21+
PlaceholderText="Add actions"
22+
QueryIcon="{ui:FontIconSource Glyph=&#xE721;,
23+
FontSize=12}"
24+
SuggestedItemsSource="{x:Bind _samples, Mode=OneWay}"
25+
TextChanged="TextChanged"
26+
TextMemberPath="Text"
27+
TokenDelimiter=","
28+
TokenItemAdding="TokenItemCreating">
29+
<controls:TokenizingTextBox.Header>
30+
<TextBlock>
31+
<Run Text="Start typing and select up to" />
32+
<Run FontWeight="SemiBold"
33+
Text="{Binding MaximumTokens, ElementName=TokenBox, Mode=OneWay}" />
34+
<Run Text="actions" />
35+
</TextBlock>
36+
</controls:TokenizingTextBox.Header>
37+
<controls:TokenizingTextBox.SuggestedItemTemplate>
38+
<DataTemplate>
39+
<StackPanel Orientation="Horizontal">
40+
<Viewbox Width="16">
41+
<SymbolIcon Symbol="{Binding Icon}" />
42+
</Viewbox>
43+
<TextBlock Padding="8,0,0,0"
44+
Text="{Binding Text}" />
45+
</StackPanel>
46+
</DataTemplate>
47+
</controls:TokenizingTextBox.SuggestedItemTemplate>
48+
<controls:TokenizingTextBox.TokenItemTemplate>
49+
<DataTemplate>
50+
<StackPanel Orientation="Horizontal">
51+
<Viewbox Width="16">
52+
<SymbolIcon Symbol="{Binding Icon}" />
53+
</Viewbox>
54+
55+
<TextBlock Padding="8,0,0,0"
56+
Text="{Binding Text}" />
57+
</StackPanel>
58+
</DataTemplate>
59+
</controls:TokenizingTextBox.TokenItemTemplate>
60+
</controls:TokenizingTextBox>
61+
62+
63+
<TextBlock Margin="0,24,0,0"
64+
FontWeight="SemiBold"
65+
Text="Text:" />
66+
<TextBlock x:Name="currentEdit" />
67+
68+
<TextBlock Margin="0,24,0,0"
69+
FontWeight="SemiBold"
70+
Text="SelectedTokenText:" />
71+
<TextBlock x:Name="selectedItemsString" />
72+
73+
<TextBlock Margin="0,24,0,0"
74+
FontWeight="SemiBold"
75+
Text="Items:" />
76+
<ItemsControl ItemsSource="{x:Bind SelectedTokens, Mode=OneWay}" />
77+
78+
<TextBlock Margin="0,24,0,0"
79+
FontWeight="SemiBold"
80+
Text="Clicked item:" />
81+
<TextBlock x:Name="clickedItem" />
82+
</StackPanel>
83+
</Page>
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using CommunityToolkit.WinUI.Controls;
6+
7+
namespace TokenizingTextBoxExperiment.Samples;
8+
9+
[ToolkitSample(id: nameof(TokenizingTextBoxSample), "Basic sample", description: $"A sample for showing how to create and use a {nameof(TokenizingTextBox)}.")]
10+
public sealed partial class TokenizingTextBoxSample : Page
11+
{
12+
public readonly List<SampleDataType> _samples = new List<SampleDataType>()
13+
{
14+
new SampleDataType() { Text = "Account", Icon = Symbol.Account },
15+
new SampleDataType() { Text = "Add friend", Icon = Symbol.AddFriend },
16+
new SampleDataType() { Text = "Attach", Icon = Symbol.Attach },
17+
new SampleDataType() { Text = "Attach camera", Icon = Symbol.AttachCamera },
18+
new SampleDataType() { Text = "Audio", Icon = Symbol.Audio },
19+
new SampleDataType() { Text = "Block contact", Icon = Symbol.BlockContact },
20+
new SampleDataType() { Text = "Calculator", Icon = Symbol.Calculator },
21+
new SampleDataType() { Text = "Calendar", Icon = Symbol.Calendar },
22+
new SampleDataType() { Text = "Camera", Icon = Symbol.Camera },
23+
new SampleDataType() { Text = "Contact", Icon = Symbol.Contact },
24+
new SampleDataType() { Text = "Favorite", Icon = Symbol.Favorite },
25+
new SampleDataType() { Text = "Link", Icon = Symbol.Link },
26+
new SampleDataType() { Text = "Mail", Icon = Symbol.Mail },
27+
new SampleDataType() { Text = "Map", Icon = Symbol.Map },
28+
new SampleDataType() { Text = "Phone", Icon = Symbol.Phone },
29+
new SampleDataType() { Text = "Pin", Icon = Symbol.Pin },
30+
new SampleDataType() { Text = "Rotate", Icon = Symbol.Rotate },
31+
new SampleDataType() { Text = "Rotate camera", Icon = Symbol.RotateCamera },
32+
new SampleDataType() { Text = "Send", Icon = Symbol.Send },
33+
new SampleDataType() { Text = "Tags", Icon = Symbol.Tag },
34+
new SampleDataType() { Text = "UnFavorite", Icon = Symbol.UnFavorite },
35+
new SampleDataType() { Text = "UnPin", Icon = Symbol.UnPin },
36+
new SampleDataType() { Text = "Zoom", Icon = Symbol.Zoom },
37+
new SampleDataType() { Text = "ZoomIn", Icon = Symbol.ZoomIn },
38+
new SampleDataType() { Text = "ZoomOut", Icon = Symbol.ZoomOut },
39+
};
40+
41+
public ObservableCollection<SampleDataType> SelectedTokens { get; set; }
42+
43+
public TokenizingTextBoxSample()
44+
{
45+
this.InitializeComponent();
46+
SelectedTokens = new()
47+
{
48+
_samples[0],
49+
_samples[1]
50+
};
51+
52+
}
53+
54+
private void TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
55+
{
56+
currentEdit.Text = TokenBox.Text;
57+
SetSelectedTokenText();
58+
}
59+
60+
private void SetSelectedTokenText()
61+
{
62+
selectedItemsString.Text = TokenBox.SelectedTokenText;
63+
}
64+
65+
private void TokenItemCreating(object sender, TokenItemAddingEventArgs e)
66+
{
67+
// Take the user's text and convert it to our data type (if we have a matching one).
68+
#if !HAS_UNO
69+
e.Item = _samples.FirstOrDefault((item) => item.Text!.Contains(e.TokenText, StringComparison.CurrentCultureIgnoreCase));
70+
#else
71+
e.Item = _samples.FirstOrDefault((item) => item.Text!.Contains(e.TokenText));
72+
#endif
73+
// Otherwise, create a new version of our data type
74+
if (e.Item == null)
75+
{
76+
e.Item = new SampleDataType()
77+
{
78+
Text = e.TokenText,
79+
Icon = Symbol.OutlineStar
80+
};
81+
}
82+
}
83+
84+
private void TokenBox_ItemClick(object sender, ItemClickEventArgs e)
85+
{
86+
if (e.ClickedItem is SampleDataType selectedItem)
87+
{
88+
clickedItem.Text = selectedItem.Text!;
89+
}
90+
}
91+
92+
private void TokenBox_Loaded(object sender, RoutedEventArgs e)
93+
{
94+
SetSelectedTokenText();
95+
}
96+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Runtime.CompilerServices;
6+
7+
// These `InternalsVisibleTo` calls are intended to make it easier for
8+
// for any internal code to be testable in all the different test projects
9+
// used with the Labs infrastructure.
10+
[assembly: InternalsVisibleTo("TokenizingTextBox.Tests.Uwp")]
11+
[assembly: InternalsVisibleTo("TokenizingTextBox.Tests.WinAppSdk")]
12+
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.Uwp")]
13+
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.WinAppSdk")]

0 commit comments

Comments
 (0)