AutoCompleteList control

The AutoCompleteList control allows searching and selecting one or more values from a data source. The selected values must be present in the data source. This is useful when the data source contains many elements that would make the form too long or slow if displayed all at once.
 
Customization
We can set a custom data source by specifying the value ControlClass for DataSourceMode and entering the namespace and class name in the CustomControlClass control property.
 
In the GetListValuesAsync method, we need to handle both the suggestion retrieval phase (parameter Title) and the retrieval, validation, and saving of the corresponding values (parameter Text).
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using DataWeb.Data;
using DataWeb.Data.Controls;
using DataWeb.Identity;
using DataWeb.Structure;
using MyApp.Infrastructure;

namespace MyApp.DataWeb.Data.Controls
{
    public class News_UserIdMasters : AutoCompleteList
    {
        private readonly UserProfileStore userProfileStore;

        public News_UserIdMasters(Form form, IServiceProvider serviceProvider) : base(form, serviceProvider)
        {
            userProfileStore = serviceProvider.GetService<UserProfileStore>();
        }

        public override async Task<IEnumerable<List.ListItem>> GetListValuesAsync(Dictionary<string, object> parameters, IUser user, string itemId = null, NavigationContext navigationContext = null)
        {
            var userProfiles = Enumerable.Empty<UserProfile>();

            if (parameters.ContainsKey("Title"))
            {
                userProfiles = await userProfileStore.GetUserProfilesAsync(new UserProfileStore.Filter { SuggestionText = Convert.ToString(parameters["Title"]), IsPrivateAreaAccess = true });
            }
            else
            {
                // Value filter

                if (!string.IsNullOrEmpty(Convert.ToString(parameters["Value"])))
                {
                    var values = Convert.ToString(parameters["Value"]).Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    if (values.Length != 0)
                    {
                        userProfiles = await userProfileStore.GetUserProfilesAsync(new UserProfileStore.Filter { IdMasters = values.ToList(), IsPrivateAreaAccess = true });
                    }
                }
            }

            return userProfiles.Select(x => new List.ListItem { Title = x.UserName, Value = x.IdMaster });
        }

        public override async Task<object> ProcessOnSaveDataAsync(object value, List<Form.ProvidedValue> providedValues, Dictionary<string, object> sectionData, IUser user, string itemId = null, NavigationContext navigationContext = null)
        {
            var listValues = await GetListValuesAsync(new Dictionary<string, object> { ["Value"] = value }, user, itemId, navigationContext);

            // Set additional data
            sectionData["UserDescriptions"] = string.Join(", ", listValues.Select(x => x.Title));

            return value;
        }
    }
}
 
In this example, we're also deriving the ProcessOnSaveDataAsync method to save the descriptions of the selected values in the database.