Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
{
/// <summary>
/// Sample of strongly-typed email address simulated data for <see cref="TokenizingTextBox"/>.
/// Sample of strongly-typed email address simulated data for <see cref="Microsoft.Toolkit.Uwp.UI.Controls.TokenizingTextBox"/>.
/// </summary>
public class SampleEmailDataType
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public sealed partial class TokenizingTextBoxPage : Page, IXamlRenderListener
private TokenizingTextBox _ttbEmail;
private ListView _ttbEmailSuggestions;
private Button _ttbEmailClear;
private Button _ttbEmailShowItems;

private AdvancedCollectionView _acv;
private AdvancedCollectionView _acvEmail;
Expand Down Expand Up @@ -117,9 +118,6 @@ public void OnXamlRendered(FrameworkElement control)
if (control.FindChildByName("TokenBox") is TokenizingTextBox ttb)
{
_ttb = ttb;

////_ttb.ItemsSource = new ObservableCollection<SampleDataType>(); // TODO: This shouldn't be required, we should initialize in control constructor???

_ttb.TokenItemAdded += TokenItemAdded;
_ttb.TokenItemRemoving += TokenItemRemoved;
_ttb.TextChanged += TextChanged;
Expand All @@ -146,8 +144,7 @@ public void OnXamlRendered(FrameworkElement control)
_ttbEmail = ttbEmail;

_ttbEmail.ItemsSource = _selectedEmails;

// _ttbEmail.ItemClick += EmailTokenItemClick;
_ttbEmail.ItemClick += EmailTokenItemClick;
_ttbEmail.TokenItemAdding += EmailTokenItemAdding;
_ttbEmail.TokenItemAdded += EmailTokenItemAdded;
_ttbEmail.TokenItemRemoved += EmailTokenItemRemoved;
Expand Down Expand Up @@ -181,9 +178,19 @@ public void OnXamlRendered(FrameworkElement control)
if (control.FindChildByName("ClearButton") is Button btn)
{
_ttbEmailClear = btn;

_ttbEmailClear.Click += ClearButtonClick;
}

if (_ttbEmailShowItems != null)
{
_ttbEmailShowItems.Click -= ShowButtonClick;
}

if (control.FindChildByName("ShowSelectedEmails") is Button showBtn)
{
_ttbEmailShowItems = showBtn;
_ttbEmailShowItems.Click += ShowButtonClick;
}
Comment on lines +183 to +193
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for the clear button

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look at that in a subsequent PR as its part of the sample app.
Merging now to get this into the toolkit release.

thanks!

}

private async void EmailTokenItemClick(object sender, ItemClickEventArgs e)
Expand Down Expand Up @@ -316,6 +323,28 @@ private void ClearButtonClick(object sender, RoutedEventArgs e)
_acvEmail.RefreshFilter();
}

private async void ShowButtonClick(object sender, RoutedEventArgs e)
{
// Grab the list of items and identify which ones are free text, which ones are tokens
string message = string.Empty;

foreach (var item in _ttbEmail.Items)
{
if (!string.IsNullOrEmpty(message))
{
message += "\r\n";
}

message += item is ITokenStringContainer ? "Unrslvd: " : "Token : ";
var textVal = item.ToString();

message += string.IsNullOrEmpty(textVal) ? "<empty>" : textVal;
}

MessageDialog md = new MessageDialog(message, "Item List with type");
await md.ShowAsync();
}

// Move to Email Suggest ListView list when we keydown from the TTB
private void EmailPreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:ex="using:Microsoft.Toolkit.Uwp.UI.Extensions"
mc:Ignorable="d">

<Grid Margin="40,40,40,40">
Expand All @@ -15,7 +16,7 @@
<controls:TokenizingTextBox
x:Name="TokenBox"
PlaceholderText="Add Actions"
QueryIcon="Setting"
QueryIcon="{ex:SymbolIconSource Glyph=Setting}"
MaxHeight="104"
HorizontalAlignment="Stretch"
TextMemberPath="Text"
Expand Down Expand Up @@ -51,7 +52,7 @@
PlaceholderText="Select Names"
MaxHeight="104"
HorizontalAlignment="Stretch"
QueryIcon="Find"
QueryIcon="{ex:SymbolIconSource Glyph=Find}"
TextMemberPath="Text"
TokenDelimiter=","
IsItemClickEnabled="True">
Expand All @@ -78,7 +79,10 @@
</ListView>
</Border>

<Button x:Name="ClearButton" Content="Clear All Tokens"/>
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
<Button x:Name="ClearButton" Content="Clear All Tokens"/>
<Button x:Name="ShowSelectedEmails" Content="Show Selected Emails" Margin="10,0,0,0"/>
</StackPanel>
</StackPanel>
</Grid>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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 Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Provides access to unresolved token string values within the tokenizing text box control
/// </summary>
public interface ITokenStringContainer
{
/// <summary>
/// Gets or sets the string text for this unresolved token
/// </summary>
string Text { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Microsoft.Toolkit.Uwp.UI.Controls
{
internal class PretokenStringContainer : DependencyObject
internal class PretokenStringContainer : DependencyObject, ITokenStringContainer
{
public string Text
{
Expand All @@ -18,13 +18,25 @@ public string Text
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register(nameof(Text), typeof(string), typeof(PretokenStringContainer), new PropertyMetadata(string.Empty));

public PretokenStringContainer()
public bool IsLast { get; private set; }

public PretokenStringContainer(bool isLast = false)
{
IsLast = isLast;
}

public PretokenStringContainer(string text)
{
Text = text;
}

/// <summary>
/// Override and provide the content of the container on ToString() so the calling app can access the token string
/// </summary>
/// <returns>The content of the string token</returns>
public override string ToString()
{
return Text;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public partial class TokenizingTextBox : ListViewBase
/// </summary>
public static readonly DependencyProperty QueryIconProperty = DependencyProperty.Register(
nameof(QueryIcon),
typeof(IconElement),
typeof(IconSource),
typeof(TokenizingTextBox),
new PropertyMetadata(null));

Expand Down Expand Up @@ -232,9 +232,9 @@ public string PlaceholderText
/// <summary>
/// Gets or sets the icon to display in the AutoSuggestBox template part.
/// </summary>
public IconElement QueryIcon
public IconSource QueryIcon
{
get => (IconElement)GetValue(QueryIconProperty);
get => (IconSource)GetValue(QueryIconProperty);
set => SetValue(QueryIconProperty, value);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ private bool MoveFocusAndSelection(MoveDirection direction)
if (index != previousIndex)
{
var newItem = ContainerFromIndex(index) as TokenizingTextBoxItem;

// Check for the new item being a text control.
// this must happen before focus is set to avoid seeing the caret
// jump in come cases
if (Items[index] is PretokenStringContainer && !IsShiftPressed)
{
newItem._autoSuggestTextBox.SelectionLength = 0;
newItem._autoSuggestTextBox.SelectionStart = direction == MoveDirection.Next
? 0
: newItem._autoSuggestTextBox.Text.Length;
}

newItem.Focus(FocusState.Keyboard);

// if no control keys are selected then the selection also becomes just this item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public TokenizingTextBox()
{
// Setup our base state of our collection
_innerItemsSource = new InterspersedObservableCollection(new ObservableCollection<object>()); // TODO: Test this still will let us bind to ItemsSource in XAML?
_currentTextEdit = _lastTextEdit = new PretokenStringContainer();
_currentTextEdit = _lastTextEdit = new PretokenStringContainer(true);
_innerItemsSource.Insert(_innerItemsSource.Count, _currentTextEdit);
ItemsSource = _innerItemsSource;
//// TODO: Consolidate with callback below for ItemsSourceProperty changed?
Expand All @@ -80,7 +80,7 @@ private void ItemsSource_PropertyChanged(DependencyObject sender, DependencyProp
if (ItemsSource != null && ItemsSource.GetType() != typeof(InterspersedObservableCollection))
{
_innerItemsSource = new InterspersedObservableCollection(ItemsSource);
_currentTextEdit = _lastTextEdit = new PretokenStringContainer();
_currentTextEdit = _lastTextEdit = new PretokenStringContainer(true);
_innerItemsSource.Insert(_innerItemsSource.Count, _currentTextEdit);
ItemsSource = _innerItemsSource;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<!-- Resources for TokenizingTextBox -->
<Thickness x:Key="TokenizingTextBoxBorderThickness">2</Thickness>
<Thickness x:Key="TokenizingTextBoxPadding">4</Thickness>
<Thickness x:Key="TokenizingTextBoxPresenterMargin">0,0,6,0</Thickness>
<x:Double x:Key="TokenizingTextBoxTokenSpacing">2</x:Double>

<controls:TokenizingTextBoxStyleSelector x:Key="TokenizingTextBoxStyleSelector"
Expand Down Expand Up @@ -89,6 +90,7 @@
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">

<ItemsPresenter Padding="{TemplateBinding Padding}"
Margin="{StaticResource TokenizingTextBoxPresenterMargin}"
Footer="{TemplateBinding Footer}"
FooterTemplate="{TemplateBinding FooterTemplate}"
FooterTransitions="{TemplateBinding FooterTransitions}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;

namespace Microsoft.Toolkit.Uwp.UI.Controls
Expand Down Expand Up @@ -76,6 +77,9 @@ private void OnApplyTemplateAutoSuggestBox(AutoSuggestBox auto)
_autoSuggestBox.PointerCaptureLost -= AutoSuggestBox_PointerExited;
_autoSuggestBox.GotFocus -= AutoSuggestBox_GotFocus;
_autoSuggestBox.LostFocus -= AutoSuggestBox_LostFocus;

// Remove any previous QueryIcon
_autoSuggestBox.QueryIcon = null;
}

_autoSuggestBox = auto;
Expand All @@ -93,6 +97,23 @@ private void OnApplyTemplateAutoSuggestBox(AutoSuggestBox auto)
_autoSuggestBox.PointerCaptureLost += AutoSuggestBox_PointerExited;
_autoSuggestBox.GotFocus += AutoSuggestBox_GotFocus;
_autoSuggestBox.LostFocus += AutoSuggestBox_LostFocus;

// Setup a binding to the QueryIcon of the Parent if we're the last box.
if (Content is PretokenStringContainer str && str.IsLast)
{
var iconBinding = new Binding()
{
Source = Owner,
Path = new PropertyPath(nameof(Owner.QueryIcon)),
RelativeSource = new RelativeSource() { Mode = RelativeSourceMode.TemplatedParent }
};

var iconSourceElement = new IconSourceElement();

iconSourceElement.SetBinding(IconSourceElement.IconSourceProperty, iconBinding);

_autoSuggestBox.QueryIcon = iconSourceElement;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,7 @@
PlaceholderText="{Binding Path=Owner.PlaceholderText, RelativeSource={RelativeSource Mode=TemplatedParent}}"
Text="{Binding Text, Mode=TwoWay}"
TextBoxStyle="{StaticResource TokenizingTextBoxTextBoxStyle}"/>
<!-- TODO: We need to only do this for our last one OR create an instance per item - QueryIcon="{Binding Path=Owner.QueryIcon, RelativeSource={RelativeSource Mode=TemplatedParent}}" -->

<!-- TODO: Visual State to style autosuggestbox based on focus -->
<!-- TODO: Visual State to style autosuggestbox based on focus? -->
</ControlTemplate>
</Setter.Value>
</Setter>
Expand Down