【问题标题】:Xamarin ProgressBar not updating real timeXamarin ProgressBar 没有实时更新
【发布时间】:2017-12-01 10:20:36
【问题描述】:

全部,

我对 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 事情有关,但不能确定。

我确信有人可以为我解答,我很感激任何即将到来的帮助。

谢谢

【问题讨论】:

  • 对于您的流开销,我建议您将流转换为 base64 字符串,这将大大减少开销
  • 谢谢哥们,我也会去看看的。这个线程的主要目的是让进度条正确更新,并且有开销,它在工作时会更清晰,但是是的,我同意,任何关于性能的东西都会检查 Base64。

标签: c# xamarin.forms async-await xamarin.ios progress-bar


【解决方案1】:

看起来是因为您在 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);
        }

【讨论】:

  • 为什么两次Task.Run?在第一次等待的结果中引入变量会更好的可读性。
  • 我不得不稍微更改您提供的代码,因为它没有编译,但这有效... await Task.Run(async () => { var song = await DependencyService.Get().GetSongs(progressUpdate); }); ...我知道这与整个异步/等待有关。我对那个 re: 整个后台任务的事情有点误解了。感谢你的回答!至于 Device.BeginInvokeOnMainThread,我以前有过,但显然它从来没有用过,因为我没有调用等式的 Task.Run 方面。
  • @VMAtm,你是对的。我不知道为什么我放了两个Task.Run。我编辑了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多