1

I have a list view that has it's IsRefreshing property binding back to a viewmodel's IsBusy property; side note i am going for an MVVM approach. The issue is this, when IsBusy is set to false, it never removes the spinning circle on the list view and it's as if the property never changes. The IsBusy property is set something like this:

public RelayCommand LoadItemsCommand
{
    get
    {
        return _loadItemsCommand
                ?? (_loadItemsCommand = new RelayCommand(
                    () =>
                    {
                        SetItems();
                    }));
    }
}


public async void SetItems()
{
    try
    {
        IsBusy = true;
        List<Item> getItems = await service.GetItems();

            //SETTING LISTS

        selectedItem = null;
        searchString = string.Empty;

        IsBusy = false;
    }
    catch (Exception a)
    {
        //log it
        IsBusy = false;
    }
}

The Set() function is being called within a page load commnad. Originally, this try/catch block was in the page load command, but tried this route as the IsBusy property never seemed to stop the listview from showing the spinning circle. I do know that this viewmodel is hooked up correctly to the view as the commands and other properties do work as they should.

private bool _IsBusy;
public bool IsBusy
{
    get { return _IsBusy; }
    set { Set("IsBusy", ref _IsBusy, value); }
}

And that is the property.

<ListView ItemsSource="{Binding items}"
                  RefreshCommand="{Binding LoadItemsCommand}"
                  IsPullToRefreshEnabled="true"
                  SelectedItem="{Binding selectedItem}"
                  IsRefreshing="{Binding IsBusy}"
                  Style="{StaticResource listViewStyle}">
        <!-- OTHER LISTVIEW STUFF -->
</ListView>

And that's the view

Michael Gulik
  • 141
  • 11
  • 1
    Adding a comment here, but is it possible that their is some sort of circular dependency thing going on between IsBusy being set within the LoadItemsCommand as they are binded to the IsRefresing/RefreshCommand, respectively? – Michael Gulik Aug 04 '17 at 12:14
  • If you set a breakpoint on IsBusy = false; does it hit it? – Stuart Aug 04 '17 at 12:24
  • can you show how Set() gets called, is it possible you are in a different instance of your ViewModel? – ajg Aug 04 '17 at 12:25
  • @Stuart yes it does get hit. I put a breakpoint at all the instances where I set IsBusy. Each time it is set to true, it always gets set back to false. – Michael Gulik Aug 04 '17 at 13:10
  • @ajg I cannot get to that Set() method as it is unique to GalaSoft(MvvmLight). I know that the Set() function works as it set's all my other objects that are binded to this view. Also, if there was another instance created, I still would have been seeing that being caught in the breakpoints. – Michael Gulik Aug 04 '17 at 13:13
  • @MichaelGulik - no, the public async void Set() method, the one you say is called from page load. – ajg Aug 04 '17 at 13:16
  • @ajg wow, my bad. I mistyped that in the original post. Corrected this issue. The function being called within the RelayCommand is the one posted below (SetItems()) – Michael Gulik Aug 04 '17 at 13:23
  • no worries, though that leaves me stumped! Maybe it is the circular reference thing mentioned above - have you tried OneWay binding? - IsRefreshing="{Binding IsBusy, Mode=OneWay}" – ajg Aug 04 '17 at 13:33
  • @MichaelGulik it is a threading issue https://stackoverflow.com/questions/20170923/relay-command-can-execute-and-a-task You should also try to avoid using `async void` unless it is an event handler. – Nkosi Aug 04 '17 at 13:37
  • @ajg yes, that was the original line, I tried removing Mode=OneWay but either way it was not working; just posted what I had at the time. – Michael Gulik Aug 04 '17 at 13:59
  • @MichaelGulik: I don't see why this would cause the problem you're seeing. Can you reduce this to a minimal, reproducible example? – Stephen Cleary Aug 04 '17 at 14:53
  • @StephenCleary Yea, that's exactly why I am really confused as to what is going on. Might be a fluke in Xamarin listviews? What would you like to see as a minimal reproducible example? – Michael Gulik Aug 04 '17 at 14:55
  • @MichaelGulik: Ideally, something I can copy/paste and run in an emulator. – Stephen Cleary Aug 04 '17 at 14:59

1 Answers1

1

You should also try to avoid using async void unless it is an event handler.

You can create an asynchronous RelayCommand by doing the following...

private Lazy<RelayCommand> _loadItemsCommand = new Lazy<RelayCommand>(() =>
    new RelayCommand(async () => await SetItems())
);
public RelayCommand LoadItemsCommand 
    get {
        return _loadItemsCommand.Value;
    }
}

public async Task SetItems() {
    try {
        IsBusy = true; // On UI Thread
        var getItems = await service.GetItems(); //asynchronous task on a background thread

        //Back on the UI Thread

        //SETTING LISTS

        selectedItem = null;
        searchString = string.Empty;

        IsBusy = false; // On UI Thread
    } catch (Exception a) {
        //log it
        IsBusy = false;
    }
}
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • that async Task SetItems try/catch block was almost what I originally had in the _loadItemsCommand. Would breaking it out like you have it create any difference? – Michael Gulik Aug 04 '17 at 14:00