Skip to content

Make TokenizingTextBox more flexible #256

Open
@minesworld

Description

@minesworld

Describe the problem

The current model only allows a single use case: adding text as AddTokenAsync() data has to be a string. Otherwise the TokenItemAdding event isn't raised and there is no chance to change the Item to be added.

By always raising the TokenItemAdding event the TokenizingTextBox could be used in ways not possible without.

Also needed: having the possibility to access the AutoSuggestBox IsSuggestionListOpen property...

Describe the solution

TokenizingTextBox.cs

if data is not a string, call the event with string.Empty and the item set to data... should be compatible this way with existing code.

   internal async Task AddTokenAsync(object data, bool? atEnd = null)
   {
       if (ReadLocalValue(MaximumTokensProperty) != DependencyProperty.UnsetValue && (MaximumTokens <= 0 || MaximumTokens <= _innerItemsSource.ItemsSource.Count))
       {
           // No tokens for you
           return;
       }

       if (TokenItemAdding != null)
       { 
           TokenItemAddingEventArgs tiaea;
           if (data is string str)
           {
               tiaea = new TokenItemAddingEventArgs(str);
           }
           else
           {
               tiaea = new TokenItemAddingEventArgs(string.Empty);
               tiaea.Item = data;
           }
       
           await TokenItemAdding.InvokeAsync(this, tiaea);

           if (tiaea.Cancel)
           {
               return;
           }

           if (tiaea.Item != null)
           {
               data = tiaea.Item; // Transformed by event implementor
           }
       }

       // If we've been typing in the last box, just add this to the end of our collection
       if (atEnd == true || _currentTextEdit == _lastTextEdit)
       {
           _innerItemsSource.InsertAt(_innerItemsSource.Count - 1, data);
       }
       else
       {
           // Otherwise, we'll insert before our current box
           var edit = _currentTextEdit;
           var index = _innerItemsSource.IndexOf(edit);

           // Insert our new data item at the location of our textbox
           _innerItemsSource.InsertAt(index, data);

           // Remove our textbox
           _innerItemsSource.Remove(edit);
       }

       // Focus back to our end box as Outlook does.
       var last = ContainerFromItem(_lastTextEdit) as TokenizingTextBoxItem;
       last?._autoSuggestTextBox.Focus(FocusState.Keyboard);

       TokenItemAdded?.Invoke(this, data);

       GuardAgainstPlaceholderTextLayoutIssue();
   }
    public bool IsSuggestionListOpen
    {
        get => (ContainerFromItem(_lastTextEdit) is TokenizingTextBoxItem lastContainer) ? lastContainer.IsSuggestionListOpen : false;
        set
        {
            if (ContainerFromItem(_lastTextEdit) is TokenizingTextBoxItem lastContainer) lastContainer.IsSuggestionListOpen = value;
        }
    }

TokenizingTextBoxItem.AutoSuggestBox.cs

    internal bool IsSuggestionListOpen
    {
        get => (_autoSuggestBox != null) ? _autoSuggestBox.IsSuggestionListOpen : false;
        set { if (_autoSuggestBox != null) _autoSuggestBox.IsSuggestionListOpen = value; }
    }

Alternatives

None

Additional info

Sorry for not providing a pull request.

Spent hours integrating the needed source files into my project in Visual Studio... . "total mess" for someone new to Windows development just wanting to code and having no clue about the tool chain.

Help us help you

None

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions