Replaced TokenSelectionMode with MaxTokens property on TokenizingTextBox
This commit is contained in:
Родитель
fbeb2c4cf6
Коммит
93ca18ad9d
|
@ -30,7 +30,7 @@
|
|||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel>
|
||||
<TextBlock FontSize="32" Text="Select Actions"
|
||||
<TextBlock FontSize="32" Text="Select up to 3 Actions"
|
||||
Margin="0,0,0,4"/>
|
||||
<controls:TokenizingTextBox
|
||||
x:Name="TokenBox"
|
||||
|
@ -40,7 +40,7 @@
|
|||
HorizontalAlignment="Stretch"
|
||||
TextMemberPath="Text"
|
||||
TokenDelimiter=","
|
||||
TokenSelectionMode="Single">
|
||||
MaxTokens="3">
|
||||
<controls:TokenizingTextBox.SuggestedItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
|
@ -76,7 +76,6 @@
|
|||
QueryIcon="{ui:SymbolIconSource Symbol=Find}"
|
||||
TextMemberPath="Text"
|
||||
TokenDelimiter=","
|
||||
TokenSelectionMode="Multiple"
|
||||
IsItemClickEnabled="True"
|
||||
TokenItemTemplate="{StaticResource EmailTokenTemplate}">
|
||||
</controls:TokenizingTextBox>
|
||||
|
|
|
@ -158,27 +158,40 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="TokenSelectionMode"/> property.
|
||||
/// Identifies the <see cref="MaxTokens"/> property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TokenSelectionModeProperty = DependencyProperty.Register(
|
||||
nameof(TokenSelectionMode),
|
||||
typeof(TokenSelectionMode),
|
||||
public static readonly DependencyProperty MaxTokensProperty = DependencyProperty.Register(
|
||||
nameof(MaxTokens),
|
||||
typeof(int?),
|
||||
typeof(TokenizingTextBox),
|
||||
new PropertyMetadata(TokenSelectionMode.Multiple, OnTokenSelectionModeChanged));
|
||||
new PropertyMetadata(null, OnMaxTokensChanged));
|
||||
|
||||
private static void OnTokenSelectionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
private static void OnMaxTokensChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is TokenizingTextBox ttb && e.NewValue is TokenSelectionMode newTokenSelectionMode && newTokenSelectionMode == TokenSelectionMode.Single)
|
||||
if (d is TokenizingTextBox ttb && e.NewValue is int newMaxTokens)
|
||||
{
|
||||
// Start at the end, remove all but the first token.
|
||||
for (var i = ttb._innerItemsSource.Count - 1; i >= 1; --i)
|
||||
var tokenCount = ttb.Items.Count;
|
||||
if (tokenCount > newMaxTokens)
|
||||
{
|
||||
var item = ttb._innerItemsSource[i];
|
||||
if (item is not ITokenStringContainer)
|
||||
int tokensToRemove = newMaxTokens - tokenCount;
|
||||
var tokensRemoved = 0;
|
||||
|
||||
// Start at the end, remove any extra tokens.
|
||||
for (var i = ttb._innerItemsSource.Count - 1; i >= 0; --i)
|
||||
{
|
||||
// Force remove the items. No warning and no option to cancel.
|
||||
ttb._innerItemsSource.Remove(item);
|
||||
ttb.TokenItemRemoved?.Invoke(ttb, item);
|
||||
var item = ttb._innerItemsSource[i];
|
||||
if (item is not ITokenStringContainer)
|
||||
{
|
||||
// Force remove the items. No warning and no option to cancel.
|
||||
ttb._innerItemsSource.Remove(item);
|
||||
ttb.TokenItemRemoved?.Invoke(ttb, item);
|
||||
|
||||
tokensRemoved++;
|
||||
if (tokensRemoved == tokensToRemove)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -332,14 +345,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how the control should display tokens.
|
||||
/// <see cref="TokenSelectionMode.Multiple"/> is the default. Multiple tokens can be selected at a time.
|
||||
/// <see cref="TokenSelectionMode.Single"/> indicates that only one token can be present in the control at a time.
|
||||
/// Gets or sets the maximum number of token results allowed at a time.
|
||||
/// </summary>
|
||||
public TokenSelectionMode TokenSelectionMode
|
||||
public int? MaxTokens
|
||||
{
|
||||
get => (TokenSelectionMode)GetValue(TokenSelectionModeProperty);
|
||||
set => SetValue(TokenSelectionModeProperty, value);
|
||||
get => (int?)GetValue(MaxTokensProperty);
|
||||
set => SetValue(MaxTokensProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,6 +77,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
if (ItemsSource != null && ItemsSource.GetType() != typeof(InterspersedObservableCollection))
|
||||
{
|
||||
_innerItemsSource = new InterspersedObservableCollection(ItemsSource);
|
||||
|
||||
if (MaxTokens.HasValue && _innerItemsSource.ItemsSource.Count > MaxTokens)
|
||||
{
|
||||
// Reduce down to the max as necessary.
|
||||
for (var i = _innerItemsSource.ItemsSource.Count; i > MaxTokens; --i)
|
||||
{
|
||||
_innerItemsSource.Remove(_innerItemsSource[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_currentTextEdit = _lastTextEdit = new PretokenStringContainer(true);
|
||||
_innerItemsSource.Insert(_innerItemsSource.Count, _currentTextEdit);
|
||||
ItemsSource = _innerItemsSource;
|
||||
|
@ -278,18 +288,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
}
|
||||
else
|
||||
{
|
||||
// TODO: It looks like we're setting selection and focus together on items? Not sure if that's what we want...
|
||||
// If that's the case, don't think this code will ever be called?
|
||||
|
||||
//// TODO: Behavior question: if no items selected (just focus) does it just go to our last active textbox?
|
||||
//// Community voted that typing in the end box made sense
|
||||
|
||||
// If no items are selected, send input to the last active string container.
|
||||
// This code is only fires during an edgecase where an item is in the process of being deleted and the user inputs a character before the focus has been redirected to a string container.
|
||||
if (_innerItemsSource[_innerItemsSource.Count - 1] is ITokenStringContainer textToken)
|
||||
{
|
||||
var last = ContainerFromIndex(Items.Count - 1) as TokenizingTextBoxItem; // Should be our last text box
|
||||
var position = last._autoSuggestTextBox.SelectionStart;
|
||||
textToken.Text = last._autoSuggestTextBox.Text.Substring(0, position) + args.Character +
|
||||
last._autoSuggestTextBox.Text.Substring(position);
|
||||
var text = last._autoSuggestTextBox.Text;
|
||||
var selectionStart = last._autoSuggestTextBox.SelectionStart;
|
||||
var position = selectionStart > text.Length ? text.Length : selectionStart;
|
||||
textToken.Text = text.Substring(0, position) + args.Character +
|
||||
text.Substring(position);
|
||||
|
||||
last._autoSuggestTextBox.SelectionStart = position + 1; // Set position to after our new character inserted
|
||||
|
||||
|
@ -432,6 +440,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
|
||||
internal async Task AddTokenAsync(object data, bool? atEnd = null)
|
||||
{
|
||||
if (MaxTokens == 0)
|
||||
{
|
||||
// No tokens for you
|
||||
return;
|
||||
}
|
||||
|
||||
if (data is string str && TokenItemAdding != null)
|
||||
{
|
||||
var tiaea = new TokenItemAddingEventArgs(str);
|
||||
|
@ -448,24 +462,29 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
}
|
||||
}
|
||||
|
||||
if (TokenSelectionMode == TokenSelectionMode.Single)
|
||||
{
|
||||
// Start at the end, remove any existing tokens.
|
||||
for (var i = _innerItemsSource.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var item = _innerItemsSource[i];
|
||||
if (item is not ITokenStringContainer)
|
||||
{
|
||||
// Force remove the items. No warning and no option to cancel.
|
||||
_innerItemsSource.Remove(item);
|
||||
TokenItemRemoved?.Invoke(this, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we've been typing in the last box, just add this to the end of our collection
|
||||
if (atEnd == true || _currentTextEdit == _lastTextEdit)
|
||||
{
|
||||
if (MaxTokens != null && _innerItemsSource.ItemsSource.Count >= MaxTokens)
|
||||
{
|
||||
// Remove tokens from the end until below the max number.
|
||||
for (var i = _innerItemsSource.Count - 2; i >= 0; --i)
|
||||
{
|
||||
var item = _innerItemsSource[i];
|
||||
if (item is not ITokenStringContainer)
|
||||
{
|
||||
_innerItemsSource.Remove(item);
|
||||
TokenItemRemoved?.Invoke(this, item);
|
||||
|
||||
// Keep going until we are below the max.
|
||||
if (_innerItemsSource.ItemsSource.Count < MaxTokens)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_innerItemsSource.InsertAt(_innerItemsSource.Count - 1, data);
|
||||
}
|
||||
else
|
||||
|
@ -474,6 +493,26 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
|
|||
var edit = _currentTextEdit;
|
||||
var index = _innerItemsSource.IndexOf(edit);
|
||||
|
||||
if (MaxTokens != null && _innerItemsSource.ItemsSource.Count >= MaxTokens)
|
||||
{
|
||||
// Find the next token and remove it, until below the max number of tokens.
|
||||
for (var i = index; i < _innerItemsSource.Count; i++)
|
||||
{
|
||||
var item = _innerItemsSource[i];
|
||||
if (item is not ITokenStringContainer)
|
||||
{
|
||||
_innerItemsSource.Remove(item);
|
||||
TokenItemRemoved?.Invoke(this, item);
|
||||
|
||||
// Keep going until we are below the max.
|
||||
if (_innerItemsSource.ItemsSource.Count < MaxTokens)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Insert our new data item at the location of our textbox
|
||||
_innerItemsSource.InsertAt(index, data);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче