簡體   English   中英

Xamarin ProgressBar 不實時更新

[英]Xamarin ProgressBar not updating real time

全部,

我是 Xamarin 的新手,更值得注意的是,C# 所以請善待......!

我有一個 Xamarin.Forms 應用程序,它使用 DependencyService 下降到 .iOS,然后遍歷我設備上的所有歌曲並使用自定義“歌曲”模型返回。

毫無疑問,有更好的方法可以做到這一點,但為了將專輯插圖返回到 PCL,我將 iOS UIImage 轉換為 System.IO.Stream 對象,然后通過 Song 模型返回它。

添加此藝術作品功能會在處理每首歌曲時產生更大的開銷。 為了嘗試讓用戶了解正在發生的事情,我在頁面上放置了一個進度條,並希望它在我每次處理一首歌曲時更新。

我的問題是,我一直無法讓進度條實時更新。 它僅在該過程完成后更新。

在這個階段我沒有使用 MVVM,所以這是背后的代碼......

using Xamarin.Forms;
using TestApplication.Interfaces;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System;

namespace TestApplication
{
    public partial class TestApplicationPage : ContentPage, INotifyPropertyChanged
    {
        private double _progress;
        public double Progress
        {
            get { return _progress; }
            set
            {
                _progress = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public TestApplication()
        {
            InitializeComponent();
            BindingContext = this;
        }

        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        async void GetNoOfSongs(object sender, System.EventArgs e)
        {
            Action<double> progressUpdate = UpdateProgress;

            var songs = await DependencyService.Get<IMedia>().GetSongs(progressUpdate);

            await DisplayAlert("No. of Songs", string.Format("You have { 0} songs on your device!", songs.Count), "Ok");
        }

        void UpdateProgress(double obj)
        {
            Progress = (double)obj;
        }
    }
}

... 這是 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:local="clr-namespace:TestApplication" x:Class="TestApplication.TestApplicationPage">
    <StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
        <Button Text="No. of Songs" Clicked="GetNoOfSongs"></Button>
        <ProgressBar Margin="20" x:Name="progressBar" Progress="{Binding Progress}" WidthRequest="400"></ProgressBar>
    </StackLayout>
</ContentPage>

這是宋模型...

using System;
using System.IO;

namespace TestApplication.Models
{
    public class Song
    {
        public string Artist { get; set; }
        public string Album { get; set; }
        public string Title { get; set; }
        public Stream Artwork { get; set; }
        public TimeSpan Duration { get; set; }
    }
}

... 這是 IMedia 界面 ...

using System.Threading.Tasks;
using System.Collections.Generic;
using TestApplication.Models;
using System;

namespace TestApplication.Interfaces
{
    public interface IMedia
    {
        Task<bool> IsAuthorised();
        Task<List<Song>> GetSongs(Action<double> callback);
    }
}

...這是 .iOS 項目中的 DependencyService 實現 ...

using TestApplication.Interfaces;
using TestApplication.Models;
using MediaPlayer;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.IO;

[assembly: Xamarin.Forms.Dependency(typeof(TestApplication.iOS.Media))]
namespace TestApplication.iOS
{
    public class Media : IMedia
    {
        public List<Song> Songs { get; private set; }

        public async Task<bool> IsAuthorised()
        {
            await MPMediaLibrary.RequestAuthorizationAsync();

            if (MPMediaLibrary.AuthorizationStatus == MPMediaLibraryAuthorizationStatus.Authorized)
                return true;
            else
                return false;
        }

        public async Task<List<Song>> GetSongs(Action<double> callback)
        {
            Songs = new List<Song> { };

            if (await IsAuthorised())
            {
                var songs = MPMediaQuery.SongsQuery.Items;
                double index = 0;

                foreach (var song in songs)
                {
                    index++;

                    callback.Invoke(index / songs.Length);

                    Stream artwork = null;

                    if (song.Artwork != null)
                        artwork = song.Artwork.ImageWithSize(song.Artwork.Bounds.Size).AsPNG().AsStream();

                    Songs.Add(new Song
                    {
                        Artist = song.AlbumArtist,
                        Album = song.AlbumTitle,
                        Title = song.Title,
                        Artwork = artwork,
                        Duration = TimeSpan.FromSeconds(song.PlaybackDuration),
                    });
                }
            }

            return Songs;
        }
    }
}

...您會看到我已將進度值綁定到一個屬性。 也許出於此功能的目的,我可以在運行時通過 ProgressBar 對象更新它,但我知道綁定有效。

我只是不明白為什么它沒有即時更新。 如果我調試,它會進入回調並更新屬性並觸發 OnPropertyChanged 事件,但 UI 直到最后才會更新。

我認為它與整個 async/await 事情有關,但不能確定。

我相信有人會為我解答,我很感激任何即將到來的幫助。

謝謝

看起來是因為您在 ui 線程中進行了所有耗時的計算。 此線程應專用於更新 ui。 如果您在此線程中進行大量計算並且想要更新 ui,它將無法工作,因為 ui 線程正忙於您的計算。 您必須做的是在另一個線程中啟動您的計算(根據您的要求使用Task.Factory.StartNewTask.Run類的東西)。 現在您正在另一個線程中運行您的長進程,您必須通過調用Device.BeginInvokeOnMainThread更新 ui 線程中的 ui。

最后,這就是你能得到的:

var songs = await Task.Run(async () => await DependencyService.Get<IMedia>().GetSongs(progressUpdate));

並且

void UpdateProgress(double obj)
        {
            Device.BeginInvokeOnMainThread(() => Progress = (double)obj);
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM