2

我有一个查询信息的过程,我想在我的 UIViewController 中接收到它时将其显示在屏幕上。我想做的是使用像这样的叠加层

https://github.com/xamarin/mobile-samples/blob/master/MWC/MWC.iOS/UI/Controls/LoadingOverlay.cs

loadingLabel.Text从 UIViewController 更新。但是,添加此视图似乎并不能立即工作 - 我猜我需要在图形更新之前退出函数调用。

什么方法可以让我显示这种类型的叠加层,并在我处理数据时让它“运行”?我是否需要将调用移动到单独的线程并通过委托函数更新显示?

4

3 回答 3

2

要让 UIKit 更新屏幕,您的代码需要运行主循环。运行主循环的简单方法是运行一些代码并返回控制,因此现有循环运行并处理您的事件(计时器、输入、显示更改)。

您可以做几件事:

  • 在后台运行任何阻塞操作,然后使用 InvokeOnMainThread 更新 UI。这意味着您的应用程序始终在运行主循环,但每隔一段时间,后台线程就会请求执行一些代码(例如显示状态)。

  • 在应用程序中间手动运行主循环。这不是一个好主意,但可以在一些非常有限的情况下工作。请参阅我在这个问题中的回答:UIAlertView 不等待

于 2013-06-21T13:59:50.957 回答
2

重新阅读和 Jason 的评论后,您可能想要执行以下操作:

        Task.Factory.StartNew (() => {

            //Do Process intensive things here

            for (int i = 0; i < 999999999; i++) {
                System.Threading.Thread.Sleep(1000);

                this.InvokeOnMainThread(() =>
                                        {
                    this.MyLabel.Text == string.Format("Counted to {0}", i);
                });
            }
        });

基本上,每当您想更新 UI 时,您都需要在主线程上进行。

于 2013-06-20T21:28:52.153 回答
0

如果你负担得起从 Alpha 通道运行 Xamarin.iOS,则可以访问 C#5 async/await。它很好地隐藏了任务和回调的复杂性。

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    muButton.TouchUpInside += DoSomething;
}

async void DoSomething (object o, EventArge e)
{
    myLabel.Text = "Starting";
    for (var i = 0; i<10;i++)
    {
        await ProcessPart(i);
        myLabel.Text = String.Format ("Progress : {i}0%", i+1);
    }

    myLabel.Text = "Done";
}

Task ProcessPart (int i)
{
    Task.Delay (1000);
}

如果您的处理足够智能以报告自己的进度,则可以将其签名更改为IEnumerable<Task<int>> Process ()并具有一个不错的刷新循环,例如:

async void DoSomething (object o, EventArge e)
{
    foreach (var tp in Process())
        myLabel.Text = String.Format ("Progress : {i}0%", await tp +1);
}

一个虚拟的 Process() 函数可能如下所示:

IEnumerable<Task<int>> Process ()
{
    for (var i=0; i<10; i++)
        yield return Task.Delay (1000).ContinueWith(x => i);
}
于 2013-06-21T14:00:30.817 回答