Source Provider - Async Query

So here is how our app is designed:
>> Model
>> Services  (Some Database Queries - All Async)
>> ViewModel (References the Model and Services)
>> View


On the view we have a dataform, and within the Dataform we are setting up a few "Pickers".
We have set the following in the View:
            InitializeComponent();
         
            ViewModel = new MyAutomobileDetailVM();
            dataForm.SourceProvider = new SourceProviderExt(ViewModel);
            BindingContext = ViewModel;

            dataForm.AutoGeneratingDataFormItem += DataForm_AutoGeneratingDataFormItem;
            dataForm.RegisterEditor("Make", "DropDown");
            dataForm.RegisterEditor("Model", "DropDown");

Within the View we have the SourceProviderExt class that Inherits SourceProvider:
class SourceProviderExt : SourceProvider
    {
        private readonly MyAutomobileDetailVM_viewModel;
        public SourceProviderExt(MyAutomobileDetailVM instance)
        {
            _viewModel = instance;
        }

        private List<Make> _make;

        List<Make> details = new List<Make>();
        public override IList GetSource(string sourceName)
        {
            
             if (sourceName == "Make")
            {

                GetSources(sourceName); 
                return details;
            }

            return new List<string>();
        }

        public async Task<IList> GetSources(string sourceName)
        {
            details = await MakeDataService.GetMakes();
            return details;
            
        }

The implementation of "MakeDataService.GetMakes" is the following in the Services package:
         public static async Task<List<Make>> GetMakes()
        {
            return await App.MobileService.GetTable<Make>().ToListAsync();
        }


Because the call is an Async control is returned before the list is returned. So I imagine an option is to make the "GetMakes" to not be an Async; however is that the best way?
If we have a form that will require alot of "Pickers", what would be a good scaleable design? When should the data be loaded? Looking for some info on this, as the above is not working, and I believe it is a design issue. The examples I have seen on here relate more to static content - populating a list via hardcoded values - though I want to do if via a call to a database returning a list.

Any help would be greatly appreciated.

Thanks



5 Replies 1 reply marked as answer

SS SaiGanesh Sakthivel Syncfusion Team May 10, 2021 12:15 PM UTC

Hi Garett,  
  
Thank you for contacting syncfusion support.  
  
#Regarding Source Provider as async in SfDataForm  
We would like to inform you that there is no possible to directly use async/await method for setting the ItemsSource of picker editor other than enum type, since the return type of GetSource override method is not supported as asynchronous method. Instead, it is possible to return a list of items included in the asynchronous method using the GetSource override method. Please refer to the code snippet for your reference.  
  
public class SourceProviderExt : SourceProvider  
 
    List<Address> details;  
    private List<Address> details1;  
    public override IList GetSource(string sourceName)  
    {  
        if (sourceName == "City")  
        {  
            GetSources(sourceName);  
            return details;  
        }  
        return new List<string>();  
    }  
    public async Task<IList> GetSources(string sourceName)  
    {  
        details =GetMakes();  
        await Task.Delay(1000);  
        return details;  
    }  
    private List<Address> GetMakes()  
    {  
        details1 = new List<Address>();  
        details1.Add(new Address() { City = "Chennai", PostalCode = 1 });  
        details1.Add(new Address() { City = "Paris", PostalCode = 2 });  
        details1.Add(new Address() { City = "Vatican", PostalCode = 3 });  
        return details1;  
    }  
 
  
We have attached the tested sample for your reference and you can download the sample from the following location. 
 
  
Please check the sample and let us know if you still facing the same issue? If not, could you please modify our sample to reproduce the issue which would be helpful for us to check on it and provide you the solution at the earliest.      
    
Regards,     
SaiGanesh Sakthivel  



GB Garett Burdey May 11, 2021 02:20 AM UTC

So we tried what you suggested:
 List<Makes> details;
 private List<Makes> details1;


        public override IList GetSource(string sourceName)
        {
            if (sourceName == "Make")
            {
                GetSources(sourceName);
                return details;
            }
            return new List<string>();      
        }


        public async Task<IList> GetSources(string sourceName)
        {
            details = await MakeDataService.GetMakes(); 
            await Task.Delay(10000);
            return details;
        }


and the following is our "MakeDataService.GetMakes()":

public static async Task<List<Make>> GetMakes()
{
            return await App.MobileService.GetTable<Make>().ToListAsync();
}

when we run the above we get the following exception:
System.ArgumentNullException: 'Value cannot be null.
Parameter name: source'



So it seems as though control is being passed back to the call before the database has returned values. So we are thinking, should the call (query) be synchronous?
Note we also tried setting the wait/delay to 1000000 and still no luck. I do think setting a delay is not ideal if that is part of the solution given if the database response changes slightly we may encounter exceptions and again have to revisit the delay.

Thoughts on this... Any help would be really appreciated. We feel like we are getting close.

Thanks








SS SaiGanesh Sakthivel Syncfusion Team May 11, 2021 12:49 PM UTC

Hi Garett,   
   
Thank you for contacting syncfusion support.   
   
#Regarding Source Provider as async in SfDataForm   
We would like to inform you that as per implementation of SfDataForm, the source provider does not support the asynchronous process. Since, we suggest to you to use the AutoGeneratingDataFormItem event. Inside the event, set the itemsource for the DataFormDatePicker. Please refer to the code snippet for your reference. 
 
Code Snippet 
private async void DataForm_AutoGeneratingDataFormItem(object sender, AutoGeneratingDataFormItemEventArgs e) 
{ 
    if (e.DataFormItem != null && e.DataFormItem.Name == "City") 
    { 
        if (Device.RuntimePlatform != Device.UWP) 
        { 
            (e.DataFormItem as DataFormPickerItem).DisplayMemberPath = "City"; 
            (e.DataFormItem as DataFormPickerItem).ValueMemberPath = "PostalCode"; 
            await GetSources(); 
            (e.DataFormItem as DataFormPickerItem).ItemsSource = details; 
        } 
    } 
} 
 
Please refer to the tested sample in the following location. 
 
Please let us know if you still facing the same issue?. We would like to set up a web meeting with you to look into it and provide resolution. Would you please let me know of your availability for this? Our team will make every effort to have this scheduled on a date and time according to your convenience. 
 
Regards, 
SaiGanesh Sakthivel

Marked as answer

GB Garett Burdey May 14, 2021 12:54 AM UTC

Thank you for your assistance on this, as it has provided many insights; however we have taken the approach of loading all of the data as part of the App OnStart method and reference from there.

Thanks again for the support!


MS Muniappan Subramanian Syncfusion Team May 14, 2021 12:33 PM UTC

Hi Garett, 
 
Thank you for the update. 
 
We are glad that our solution meets your requirement. Please let us know if you need any further update. As always, we are happy to help you out. 
 
Regards, 
Muniappan S. 


Loader.
Up arrow icon