Xamarin - 将 ActivityIndi​​cator 可见性绑定到异步任务完成

Xamarin - Bind ActivityIndicator visibility to async Task finished

我正在根据这个答案将图像异步加载到我的列表视图中:

我想在页面从 Web 加载数据时显示 ActivityIndi​​cator,但不知道如何将它的可见性绑定到任务,以便在任务加载完成后消失。

我在我的 ViewModel 中创建了一个 isLoading 布尔变量。

我在我的 ViewModel 中以这种方式尝试过,但它不起作用:

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

        isLoading = false;

我也试过在Task中设置,但是isLoading总是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;
    }

我的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>

我的视图模型:

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;
    }

}
}

画廊服务:

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
    }
}

你应该这样使用ActivityIndicator

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

使用 IsRunning 属性 与 IsBusy 属性

    private bool _isBusy;

    public bool IsBusy
    {
        get
        {
            return _isBusy;
        }

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

在视图模型中

  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;
    }
}

另一个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;
        }
    }