Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Using Async in Xamarin Forms

I've created a new Xamarin Forms PCL project for iOS, Windows Phone and Android. I seem to be tying myself up in knots with async methods. The new Xamarin Forms Templates do not seem to be set up with async in mind, but two libraries I'm using are both async ones.

I tried adding awaits and marking method as async as required, but once GetMainPage() became async which is called in the individual platform projects in some of them it was called by a constructor so could not be async.

Is there a nice cross platform Xamarin Forms Example that uses Async await that would be good to learn from?

Or is there some guidance about which Xamarin Forms existing methods should be marked as async or on how you can call an async method from a method that can't be marked as async.

I've found that I can make the project compile without some methods being marked as async, but on some platforms it hangs when a async method is called.

Posts

  • MihaMarkicMihaMarkic SI ✭✭✭✭

    GetMainPage is not a good canidate for async because it has to be created on UI thread and it doesn't take much time. You'd typically use async methods with longer tasks and I/O bound methods (i.e. communicating with server, working with file system, ...) IOW use async where it makes sense, not everywhere. It is not a magic wand or something you have to use to be modern :)

  • RichardGarsideRichardGarside GBMember ✭✭

    If I need to load some data when my app starts, where is the best place to do this? I was doing this in GetMainPage, but I can see why this wouldn't be a good idea.

  • MihaMarkicMihaMarkic SI ✭✭✭✭

    You can start loading data (in async) way from within GetMainPage, but you wouldn't wait for it. Just fire & forget and do something when it is loaded, i.e.:

    public class SomePage {
       public SomePage() {
         var ignore = LoadData();
      }
    
            async Task LoadData() {
               await LoadingDataFromServer();
               dataLoadedLabel.Text = "Loaded";
            }
    }
    
  • adamkempadamkemp USInsider, Developer Group Leader mod

    You don't need the var ignore. Just make the function async void instead of async Task.

  • MihaMarkicMihaMarkic SI ✭✭✭✭

    Well, it depends whether you need var ignore or not. In the case when you want to await it (perhaps calling it from within another method) it makes sense to return Task instance and thus ignore the warning when you don't await it.

  • Josh_QuintusJosh_Quintus USMember ✭✭

    You probably do NOT want to just call the async task and not wait for it to complete like that. In fact, doing so should generate compiler warnings. The problem is that you won't see any exceptions that are raised by LoadData. For more information on this I highly recommend the Patterns for Asynchronous MVVM of articles on MSDN. If you want, you can skip directly to the bit about NotifyTaskCompletion.

    In addition to reporting errors, NotifyTaskCompletion will allow you to bind elements in the UI to whether or not the data has finished loading (i.e., an activity indicator can spin until you have your data).

    I have an example of using this in a Xamarin Forms app on my blog Xamarin.Forms: Shopping Cart Day 2

    Here's a quick example of how to use it:

    public class MyViewModel
    {
      public MyViewModel()
      {
         Categories = new NotifyTaskCompletion<List<DataItem>>(LoadData());
      }
    
      public NotifyTaskCompletion<List<DataItem>> Categories {get; private set;}
    
      private async Task<List<DataItem>> LoadData() 
      {
         return await LoadingDataFromServer();
      }
    }
    
  • adamkempadamkemp USInsider, Developer Group Leader mod

    You won't get a warning if you use async void, but you do have to be very careful with exceptions. I usually use a try/catch in any async void methods.

  • Hi, i'm trying to use the NotifyTaskCompletion class in my proyect but i dont have any result and i can't find what it's wrong in my code. I'm following the example that Josh posted for retrieve data from a web service ... here is my code:

    public class ProductsViewModel
    {
        private readonly ODataClient _client = new ODataClient(new ODataClientSettings("http://networkerproservice2.azurewebsites.net/kraken/") { PayloadFormat = ODataPayloadFormat.Json });
        public NotifyTaskCompletion<List<Products>> Products { get; private set; }
        public ProductsViewModel()
        {
            Products = new NotifyTaskCompletion<List<Products>>(GetAll());
        }
    
        public async Task<List<Products>> GetAll()
        {
            var datos = await _client.For<Products>().FindEntriesAsync();
            return (List<Products>)datos;
        }
    }
    
  • MihaMarkicMihaMarkic SI ✭✭✭✭

    Indeed that's the case with async void. It will nuke your app if exception is unhandled while async Task won't.

  • rene_ruppertrene_ruppert DEXamarin Team, University, XamUProfessors Xamurai

    If you don't want to or cannot make the caller method async, want to get the potential exceptions of your async method and do not want to use a pragma or live with a compiler warning, her's another (simple) option you might consider:

    public class SomePage
    {
      public SomePage() {
    
      var t = LoadDataAsync();
      t.ContinueWith(task => {
        /* Log issue, deal with it or whatever! */ 
      }, TaskContinuationOptions.OnlyOnFaulted);
    }
    
    async Task LoadDataAsync()
    {
               await LoadingDataFromServer();
               dataLoadedLabel.Text = "Loaded";
            }
    }
    

    By the way: I recommend naming async methods FooAsync() to make clear they are async. Also see: http://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_NamingConvention

  • MihaMarkicMihaMarkic SI ✭✭✭✭

    Marking the method as async and using try/catch is still much readable. IMHO. But that will work, too. And don't forget to use TaskScheduler.FromCurrentSynchronizationContext to continue in UI thread.

  • hvaughanhvaughan USMember ✭✭✭

    @Josh_Quintus

    I got the NotifyTaskCompletion working in my ViewModel. I am wondering if I can work with the the NotifyTaskCompletion<T> property directly using .Result(), once the data has already been loaded into it? Or would it be better to create a backing variable or something like that and do basic processing on it instead?

    For example, if I have public NotifyTaskCompletion<List<Profile>> ProfileAsync { get; private set; } with data in it, and then a user clicks on it and I want to do a .Count(), what would be best? I ask because I do not see any examples of people using it other than to simply load the view (maybe that is a sign I should not be using it in this way).

  • HrishiDHrishiD INMember ✭✭

    @Josh_Quintus @rene_ruppert

    Hi,
    I am having two three methods returning collection that are async I have to call them in constructor and from those collections I need to have some sort of properties that are bound to xaml.

    public class MyViewModel
    {
    public MyViewModel()
    {
    Categories = new NotifyTaskCompletion<List>(LoadData());
    }

    public NotifyTaskCompletion<List> Categories {get; private set;}

    private async Task<List> LoadData()
    {
    return await LoadingDataFromServer();
    }
    }

    above things seems to be useful. Gone through your blog and what if I have two async methods like loaddata1() and loaddata2() and I dont want Categories.result directly in Xaml but I want it to be in ViewModel and extract some properties out of it and then bind to the view.
    suppose I have one button getUpdate() and I want to update this categories.result list how that can be handled.

    Gone through https://msdn.microsoft.com/magazine/jj991977 this and many more async await articles.

    I have my serivices returning collections and nested collections and proerties. :(

    Can any one give solution?

    Or should I drop MVVM and do call async mthods in code behind.

    Thanks For it.

  • HrishiDHrishiD INMember ✭✭

    @hvaughan Did you find any solution

  • hvaughanhvaughan USMember ✭✭✭
    edited October 2015

    @HrishiD

    First off, I have since started trying to just load any and all data that I can from within OnAppearing() (calling ViewModel methods), since it is able to be async properly. So I would suggest doing that instead, if possible.

    Otherwise, I got it to work but not sure if this is exactly what you might need, but this is how I did it using MVVM, and I realize it is kind of a lame way and may defeat the entire purpose but I never got an answer back on this thread. Which is also why I suggest running LoadData() from your code-behind's OnAppearing().

    Using the code you put in above, I would create another property (lets call it NormalCategories that is the same type as Categories but without the NotifyTaskCompletion part. Then within LoadData(), I would assign the result of LoadingDataFromServer() to NormalCategories, and then return it as well, like so:

    Code (let say Categories is a NotifyTaskCompletion<List<string>>):

    public class MyViewModel {
    
        public MyViewModel() {
            Categories = new NotifyTaskCompletion<List<string>>(LoadData());
        }
    
        public List<string> NormalCategories {get; private set;}
        public NotifyTaskCompletion<List<string>> Categories {get; private set;}
    
        private async Task<List<string>> LoadData() {
            NormalCategories = await LoadingDataFromServer();
            return NormalCategories;
        }
    }
    
Sign In or Register to comment.