-
Notifications
You must be signed in to change notification settings - Fork 56
How to add a new item to a list?
The SimpleDemo
project shows how to do it. I'll explain here how you can easily add a new item and bind it.
We have a collection of fruits. User can select a fruit from the control by typing. The UI displays the fruit selection from the fruit list provider and displays what user has typed, this is done by data binding. When the control has lost focus we check whether any fruit was selected, and the typed fruit is in the list. If all this is false, we ask user to add the new typed fruit to the list.
Fruit provider doesn't have the fruit list within it, but receives a reference of an external list. The fruit provider only provides a way to search the fruit list.
public sealed class FruitsProvider : ISuggestionProvider
{
private readonly ObservableCollection<string> fruits;
public IEnumerable GetSuggestions(string filter)
{
return fruits.Where(x => x.StartsWith(filter, StringComparison.InvariantCultureIgnoreCase));
}
public FruitsProvider(ref ObservableCollection<string> fruits)
{
this.fruits = fruits;
}
}
The viewmodel itself has the ObservableCollection to hold the fruit list, and it is initialized in the viewmodel constructor. The viewmodel also has a Fruit provider instance, exposed as a property.
public MainWindowViewModel()
{
Fruits = new ObservableCollection<string>();
Fruits.Add("apple");
Provider = new FruitsProvider(ref fruits);
}
Also, the viewmodel exposes properties we use to know what was typed and what is selected.
private string selectedFruit;
public string SelectedFruit
{
get => selectedFruit;
set
{
selectedFruit = value;
OnPropertyChanged();
}
}
private string typedFruit;
public string TypedFruit
{
get => typedFruit;
set
{
typedFruit = value;
OnPropertyChanged();
}
}
See how the Provider is bound to the control below (XAML), it's using data binding. You don't need a static resource. Also see how the other properties are bound.
<editors:AutoCompleteTextBox
Grid.Row="3"
Width="150"
Height="26"
Margin="20"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Provider="{Binding Provider}"
SelectedItem="{Binding SelectedFruit, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding TypedFruit, UpdateSourceTrigger=PropertyChanged}"
Watermark="Enter a fruit">
<editors:AutoCompleteTextBox.LoadingContent>
<TextBlock
Margin="5"
FontSize="14"
Text="Loading..." />
</editors:AutoCompleteTextBox.LoadingContent>
<i:Interaction.Triggers>
<i:EventTrigger EventName="LostFocus">
<i:InvokeCommandAction Command="{Binding ConfirmAddCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</editors:AutoCompleteTextBox>
To know when to add an item to the list we are using the LostFocus event, but any other way can be used, like a KeyBindings to link this action to a pressed key (i.e, F4).
So, when the control lost focus we call the command from the ViewModel. This is only a demo, you can use the Command implementation you want. Here I'm using the Community.Toolkit.Mvvm.
[RelayCommand]
private void ConfirmAdd()
{
if (SelectedFruit == null && !Fruits.Any(x => x.Equals(TypedFruit, System.StringComparison.InvariantCultureIgnoreCase)))
{
if (MessageBox.Show($"Fruit {TypedFruit} isn't in the list. Do you want to add it?", "Question", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
Fruits.Add(TypedFruit);
SelectedFruit = Fruits.First(x => x == TypedFruit);
}
}
}
In this command we check if there's no item selected and if the typed fruit isn't in the list. If all that is true, means the entered text might be a new fruit to be added, so we ask the user.
As you can see, it's not difficult to implement this feature in your app using the WPF-AutoComplete-TextBox