Home > database >  Calling async method from MVVM property
Calling async method from MVVM property

Time:03-18

I'm implementing my own version of auto-complete in a view model in my Xamarin Forms 5 app.

I need to call an async look up function from the Keyword MVVM property. Not sure if I'm handling it right. See below:

string keyword { get; set; }
ObservableRangeCollection<string> suggestions = new ObservableRangeCollection<string>();
public string Keyword
{
   get => keyword;
   set
   {
      if(keyword == value)
         return;

      keyword = value;
      OnPropertyChanged();

      // If keyword has at least 3 characters, get suggestions
      if(keyword.length > 2)
         GetSuggestions(keyword).Wait();
   }
}

ObservableRangeCollection<string> Suggestions
{
   get => suggestions;
   set
   {
      if(sugggestions == value)
         return;

      suggestions = value;
      OnPropertyChanged();
   }
}

async Task GetSuggestions(string searchKeyword)
{
   var result = await _myApiService.GetSuggestions(searchKeyword);
   if(result != null)
   {
      Suggestions = new ObservableRangeCollection(result);
      OnPropertyChanged(Suggestions);
   }
}

I'd appreciate any corrections or suggestions. Thanks.

CodePudding user response:

You definitely don't want to block on async code here (as explained on my blog). More generally, you don't want to block the UI, especially when your users are interacting with it (i.e., typing).

Instead, use a pattern like async data binding to (synchronously) start the operation, and then update your UI when the results come in.

E.g., using NotifyTask<T> from here:

string keyword { get; set; }
NotifyTask<List<string>> suggestions;
public string Keyword
{
   get => keyword;
   set
   {
      if (keyword == value)
         return;

      keyword = value;
      OnPropertyChanged();

      // If keyword has at least 3 characters, get suggestions
      if (keyword.length > 2)
         suggestions = NotifyTask.Create(GetSuggestionsAsync(keyword));
   }
}

NotifyTask<List<string>> Suggestions
{
   get => suggestions;
}

async Task<List<string>> GetSuggestionsAsync(string searchKeyword)
{
   return await _myApiService.GetSuggestions(searchKeyword);
}

Then, instead of data-binding to Suggestions as a collection of string, data-bind to Suggestions.Result instead. You can also data-bind to Suggestions.IsCompleted (or Suggestions.IsNotCompleted) to show a loading/busy indicator, and Suggestions.IsFaulted to show an error message.

  • Related