【问题标题】:Access UI Control from another class从另一个类访问 UI 控件
【发布时间】:2018-01-29 16:19:12
【问题描述】:

我想从另一个班级更新我的进度视图,但不知道如何正确执行。

在我的 ViewController 中,我有一个启动任务的按钮,该按钮从硬编码链接下载文件

public void downloadTask()
        {
            NSUrl url = NSUrl.FromString("https://www.dropbox.com/s/5fsciuo0nprzvu6/TestDoc.docx?dl=0");

            var config = NSUrlSessionConfiguration.DefaultSessionConfiguration;
            NSUrlSession session = NSUrlSession.FromConfiguration(config, (new SimpleSessionDelegate() as INSUrlSessionDelegate), new NSOperationQueue());
            var downloadTask = session.CreateDownloadTask(NSUrlRequest.FromUrl(url));

            downloadTask.Resume();
        }

在我的 SimpleSessionDelegate 类中,我想在 DidWriteData 方法中更新我的进度视图。

public class SimpleSessionDelegate : NSUrlSessionDownloadDelegate
    {
        public override void DidFinishDownloading(NSUrlSession session, NSUrlSessionDownloadTask downloadTask, NSUrl location)
        {
            var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var destinationPath = Path.Combine(documents, "Sample.docx");

            if (File.Exists(location.Path))
            {
                NSFileManager fileManager = NSFileManager.DefaultManager;
                NSError error;

                fileManager.Remove(destinationPath, out error);

                bool success = fileManager.Copy(location.Path, destinationPath, out error);

                if (!success)
                {
                    Console.WriteLine("Error during the copy: {0}", error.LocalizedDescription);
                }
            }
        }
        public override void DidWriteData(NSUrlSession session, NSUrlSessionDownloadTask downloadTask, long bytesWritten, long totalBytesWritten, long totalBytesExpectedToWrite)
        {
            new System.Threading.Thread(new System.Threading.ThreadStart(() =>
            {
                InvokeOnMainThread(() =>
                {
                    //how to access UI?
                });
            })).Start();
        }
    }

【问题讨论】:

  • 您最好在 ViewController 中设置一个计时器,每隔一秒左右向您的 SimpleSessionDelegate 询问文件下载的状态,并根据需要进行更新。
  • 那么直接在 didWriteData 方法中更新进度视图是性能杀手吗?
  • 主要原因是将 UI 代码排除在文件下载代码之外。更干净
  • @R.Kut 你好,你的问题解决了吗?

标签: ios xamarin background nsurlsession


【解决方案1】:

你可以尝试使用 Event 来改变你的 ViewController 的 UIProgressView 的进度。

首先在你的 ViewModel 中定义一个事件:

public delegate void DownloadProgressDelegate(float progress);
public event DownloadProgressDelegate DownloadEvent;

其次,将此事件传递给您的下载委托文件:

NSUrlSession session = NSUrlSession.FromConfiguration(config, (new SimpleSessionDelegate(DownloadEvent) as INSUrlSessionDelegate), new NSOperationQueue());
//Here is your SimpleSessionDelegate
event ViewModel.DownloadProgressDelegate DownloadEvent;
public SimpleSessionDelegate(ViewModel.DownloadProgressDelegate downloadEvent)
{
    DownloadEvent = downloadEvent;
}

那么当menthodDidWriteData()有数据进来的时候就可以触发这个事件:

float progress = (float)totalBytesWritten / totalBytesExpectedToWrite;
DownloadEvent(progress);

最后一步是在您的 ViewController 中订阅此事件,例如:

var myViewModel = new ViewModel();
MyViewModel.DownloadEvent += (progress) =>
{
    MyProgress.Progress = progress;
};
myViewModel.downloadTask();

【讨论】:

  • 我无法将事件传递给我的 SimpleSessionDelegate,因为基类 NSUrlSessionDownloadDelegate 没有这样的构造函数
  • @R.Kut 您可以使用参数downloadEvent创建自己的构造函数。
  • 是的,在我的 SimpleSessionDelegate 中,但不在 NSUrlSessionDownloadDelegate 中,因为那来自元数据。
  • @R.Kut 我在我的示例here 中模拟了一个任务下载。
  • 一些附加信息:计算正确的方法float progress = float()totalBytesExpectedToWrite / (float)totalBytesWritten and myProgressBar.SetProgress(progress, true);
【解决方案2】:

在您的Page.xaml 中执行以下操作:

<ContentPage .... >
    ...
    <ProgressBar Progress="{Binding ProgValue, Mode=TwoWay}" />
    ...
</ContentPage>

然后在Page.xaml.cs 中执行此操作:

...
public partial class Page : ContentPage
{
    InitializeComponent();
    BindingContext = new PageViewModel();
}
...

现在您需要PageViewModel 类在您的数据(模型)和您的视图之间创建一种方式:

using MvvmHelper;
using System;

namespace MyApp.ViewModels
{
    ...
    public class PageViewModel : BaseViewModel
    {
        ...
        public static int ProgValue { get; set; }
        ...
    }
}

现在,如果您从应用程序的每个位置更新 ProgValue 的值,它将自动更新进度条。

要使用BaseViewModel,需要安装
Mvvm Helper
或在包管理器控制台中输入:
Install-Package Refractored.MvvmHelpers

这种架构称为 MVVM(模型-视图-视图-模型)——正式名称为 MVC(模型-视图-控制器)

【讨论】:

  • 在哪里可以找到 page.xaml?它是一个 iOS 单视图应用程序
  • 我为 Xamarin.Forms 编写了这个示例,用于跨平台使用。在 iOS 特定项目中,你有 page.storyborad,阅读这个苹果开发者文档:Connect UI to code
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-06
  • 2019-09-23
相关资源
最近更新 更多