Xamarin - Bind ActivityIndicator visibility to async Task finished

大憨熊 提交于 2020-03-25 16:08:33

问题


I'm loading images async into my Listview according to this answer: Xamarin - Asynchronous data binding

I'd like to display a ActivityIndicator while the page is loading the data from the web, but cannot figure out how to bind the visibility it to the task, so that it disappears when the task is done loading..

I've created a isLoading bool variable in my ViewModel.

I tried it this way in my ViewModel, but It's not working:

        isLoading = true;
        GetImagesCommand = new Command(async () => await DoGetImagesCommand(pCode, gCode, gUrl));

        isLoading = false;

I also tried setting it in the Task, but isLoading is always false..

 private async Task DoGetImagesCommand(string pCode, string gCode, string gUrl)
    {
        isLoading = true;
        var images = await _galleryService.GetImageList(pCode, gCode, gUrl);
        foreach (var image in images)
            Galleries.Add(image);
        isLoading = false;
    }

my Xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:vm="clr-namespace:GalShare.ViewModel"
         xmlns:d="http://xamarin.com/schemas/2014/forms/design"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms" xmlns:forms="clr-namespace:RedCorners.Forms;assembly=RedCorners.Forms"
         mc:Ignorable="d"
         x:Class="GalShare.Views.Gallery">

<ContentPage.Content>
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
        <StackLayout
             AbsoluteLayout.LayoutFlags="All"
             AbsoluteLayout.LayoutBounds="0,0,1,1">
            <CollectionView ItemsSource="{Binding Galleries}" x:Name="MyCollection" SelectionMode="Single" SelectionChanged="CollectionView_SelectionChanged">
                <CollectionView.ItemsLayout>
                    <GridItemsLayout Orientation="Vertical"                                 
                            Span="2" />

                </CollectionView.ItemsLayout>
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <ContentView Padding="1">
                            <forms:Frame2 CornerRadius="15"  
                                   HasShadow="True"
                                   ShadowRadius="8"                               
                                   Padding="0">
                                <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="LightGray" Padding="2">
                                    <ffimageloading:CachedImage x:Name="myImage" Source="{Binding ThumbUrl}" Aspect="AspectFit" CacheDuration="0" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" DownsampleToViewSize="False"></ffimageloading:CachedImage>
                                    <Label x:Name="Picname" Text="{Binding ImageName}" IsVisible="{Binding showName}" VerticalOptions="StartAndExpand" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" ></Label>
                                </StackLayout>
                            </forms:Frame2>
                        </ContentView>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </StackLayout>
        <StackLayout IsVisible="{Binding isLoading}" x:Name="LoadingLayout" Padding="12"
             AbsoluteLayout.LayoutFlags="PositionProportional"
             AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1">
            <ActivityIndicator  />
            <Label Text="Loading gallery..." HorizontalOptions="Center" TextColor="Black"/>
        </StackLayout>
    </AbsoluteLayout>

</ContentPage.Content>

my ViewModel:

namespace GalShare.ViewModel
{
class GalleryViewModel
{
    public string pCode { get; set; }
    public string gCode { get; set; }
    public string gUrl { get; set; }
    public bool isLoading { get; set; }
    public bool showname { get; set; }
    public ObservableCollection<picdata> Galleries { get; } = new ObservableCollection<picdata>();

    public ICommand GetImagesCommand { get; }
    private GalleryService _galleryService;

    public GalleryViewModel(string pCode, string gCode, string gUrl, string showName)
    {
        this.pCode = pCode;
        this.gCode = gCode;
        this.gUrl = gUrl;


        _galleryService = new GalleryService();



        GetImagesCommand = new Command(async () => DoGetImagesCommand(pCode, gCode, gUrl, showName));


    }

    private async Task DoGetImagesCommand(string pCode, string gCode, string gUrl, string showName)
    {
        isLoading = true;
        var images = await _galleryService.GetImageList(pCode, gCode, gUrl, showName);
        foreach (var image in images)
            Galleries.Add(image);
        isLoading = false;
    }

}
}

galleryservice:

class GalleryService
 {

    private HttpClient _httpClient;

    public GalleryService()
    {
        _httpClient = new HttpClient();
    }

    public async Task<IEnumerable<picdata>> GetImageList(string pCode, string gCode, string gUrl, string showName)
    {
        var response = await _httpClient.GetAsync(gUrl).ConfigureAwait(false);

        if (response.IsSuccessStatusCode)
        {
            var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

            //  var json = response.Content.GetStringAsync().ConfigureAwait(false);
            var deserialized = JsonConvert.DeserializeObject<JsonTxt>(json);

            bool shownametemp;
            if (showName == "1")
            {
                shownametemp = true;
            }
            else
            {
                shownametemp = false;
            }

            var images = new List<picdata>();
            foreach (var img in deserialized.Files)
            {
                images.Add(new picdata()
                {
                    ImageName = img.file,
                    BaseUrl = deserialized.Settings.Path.ToString(),
                    ThumbUrl = deserialized.Settings.Path.ToString() + "thumbs/" + img.file,
                    showname = shownametemp

                }) ;
            }

            return images;
        }

        return new picdata[0]; // return empty set
    }
}

回答1:


You sould use ActivityIndicator like that

<ActivityIndicator AbsoluteLayout.LayoutBounds="0, 0, 1, 1"
                               AbsoluteLayout.LayoutFlags="All"
                               IsVisible="{Binding IsBusy}" 
                               IsRunning="{Binding IsBusy}" 
                               Color="{StaticResource PrimaryColor}"
                               VerticalOptions="Center"
                               HorizontalOptions="Center" />

Use IsRunning property with IsBusy property

    private bool _isBusy;

    public bool IsBusy
    {
        get
        {
            return _isBusy;
        }

        set
        {
            _isBusy = value;
            RaisePropertyChanged(() => IsBusy);
        }
    }

in viewmodel

  class GalleryViewModel : ExtendedBindableObject 
{
...
     private async Task DoGetImagesCommand(string pCode, string gCode, string gUrl)
    {
        IsBusy = true;
        var images = await _galleryService.GetImageList(pCode, gCode, gUrl);
        foreach (var image in images)
            Galleries.Add(image);
        IsBusy = false;
    }
}

in another class

public abstract class ExtendedBindableObject : BindableObject
    {
        public void RaisePropertyChanged<T>(Expression<Func<T>> property)
        {
            var name = GetMemberInfo(property).Name;
            OnPropertyChanged(name);
        }

        private MemberInfo GetMemberInfo(Expression expression)
        {
            MemberExpression operand;
            LambdaExpression lambdaExpression = (LambdaExpression)expression;
            if (lambdaExpression.Body is UnaryExpression)
            {
                UnaryExpression body = (UnaryExpression)lambdaExpression.Body;
                operand = (MemberExpression)body.Operand;
            }
            else
            {
                operand = (MemberExpression)lambdaExpression.Body;
            }
            return operand.Member;
        }
    }



回答2:


Try this method where you are calling await.

try
{
    isLoading = true;
}
catch(Exception e)
{
}
finally
{
    isLoading = false;
}


来源:https://stackoverflow.com/questions/60811603/xamarin-bind-activityindicator-visibility-to-async-task-finished

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!