private async void TokenizingTextBox_CharacterReceived(UIElement sender, CharacterReceivedRoutedEventArgs args) { var container = ContainerFromItem(_currentTextEdit) as TokenizingTextBoxItem; if (container != null && !(GetFocusedElement().Equals(container._autoSuggestTextBox) || char.IsControl(args.Character))) { if (SelectedItems.Count > 0) { var index = _innerItemsSource.IndexOf(SelectedItems.First()); await RemoveAllSelectedTokens(); // Wait for removal of old items _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { // If we're before the last textbox and it's empty, redirect focus to that one instead if (index == _innerItemsSource.Count - 1 && string.IsNullOrWhiteSpace(_lastTextEdit.Text)) { var lastContainer = ContainerFromItem(_lastTextEdit) as TokenizingTextBoxItem; lastContainer.UseCharacterAsUser = true; // Make sure we trigger a refresh of suggested items. _lastTextEdit.Text = string.Empty + args.Character; UpdateCurrentTextEdit(_lastTextEdit); lastContainer._autoSuggestTextBox.SelectionStart = 1; // Set position to after our new character inserted lastContainer._autoSuggestTextBox.Focus(FocusState.Keyboard); } else { //// Otherwise, create a new textbox for this text. UpdateCurrentTextEdit(new PretokenStringContainer((string.Empty + args.Character).Trim())); // Trim so that 'space' isn't inserted and can be used to insert a new box. _innerItemsSource.Insert(index, _currentTextEdit); // Need to wait for containerization _ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { var newContainer = ContainerFromIndex(index) as TokenizingTextBoxItem; // Should be our last text box newContainer.UseCharacterAsUser = true; // Make sure we trigger a refresh of suggested items. void WaitForLoad(object s, RoutedEventArgs eargs) { if (newContainer._autoSuggestTextBox != null) { newContainer._autoSuggestTextBox.SelectionStart = 1; // Set position to after our new character inserted newContainer._autoSuggestTextBox.Focus(FocusState.Keyboard); } newContainer.Loaded -= WaitForLoad; } newContainer.AutoSuggestTextBoxLoaded += WaitForLoad; }); } }); } 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 (_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); last._autoSuggestTextBox.SelectionStart = position + 1; // Set position to after our new character inserted last._autoSuggestTextBox.Focus(FocusState.Keyboard); } } } }
private async void TokenizingTextBox_CharacterReceived(UIElement sender, CharacterReceivedRoutedEventArgs args) { var container = ContainerFromItem(_currentTextEdit) as TokenizingTextBoxItem; if (container != null && !(GetFocusedElement().Equals(container._autoSuggestTextBox) || char.IsControl(args.Character))) { if (SelectedItems.Count > 0) { var index = _innerItemsSource.IndexOf(SelectedItems.First()); await RemoveAllSelectedTokens(); // Wait for removal of old items var dispatcherQueue = DispatcherQueue.GetForCurrentThread(); _ = dispatcherQueue.EnqueueAsync( () => { // If we're before the last textbox and it's empty, redirect focus to that one instead if (index == _innerItemsSource.Count - 1 && string.IsNullOrWhiteSpace(_lastTextEdit.Text)) { var lastContainer = ContainerFromItem(_lastTextEdit) as TokenizingTextBoxItem; lastContainer.UseCharacterAsUser = true; // Make sure we trigger a refresh of suggested items. _lastTextEdit.Text = string.Empty + args.Character; UpdateCurrentTextEdit(_lastTextEdit); lastContainer._autoSuggestTextBox.SelectionStart = 1; // Set position to after our new character inserted lastContainer._autoSuggestTextBox.Focus(FocusState.Keyboard); } else { //// Otherwise, create a new textbox for this text. UpdateCurrentTextEdit(new PretokenStringContainer((string.Empty + args.Character).Trim())); // Trim so that 'space' isn't inserted and can be used to insert a new box. _innerItemsSource.Insert(index, _currentTextEdit); // Need to wait for containerization _ = dispatcherQueue.EnqueueAsync( () => { var newContainer = ContainerFromIndex(index) as TokenizingTextBoxItem; // Should be our last text box newContainer.UseCharacterAsUser = true; // Make sure we trigger a refresh of suggested items. void WaitForLoad(object s, RoutedEventArgs eargs) { if (newContainer._autoSuggestTextBox != null) { newContainer._autoSuggestTextBox.SelectionStart = 1; // Set position to after our new character inserted newContainer._autoSuggestTextBox.Focus(FocusState.Keyboard); } newContainer.Loaded -= WaitForLoad; } newContainer.AutoSuggestTextBoxLoaded += WaitForLoad; }, DispatcherQueuePriority.Normal); } }, DispatcherQueuePriority.Normal); } else { // 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 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 last._autoSuggestTextBox.Focus(FocusState.Keyboard); } } } }