代码之家  ›  专栏  ›  技术社区  ›  nicks

为什么标签文本没有立即更改?

  •  1
  • nicks  · 技术社区  · 8 年前

    我试着测试 ModernHttpClient ,当我遇到以下情况时:标签没有更新,在下面的代码中两个按钮都没有被立即禁用(在Nexus 5x上测试),而是等待点击被处理直到结束!那是什么,我的一个错误,一个bug还是一个奇怪的“优化”特性?

    第1.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"
                 x:Class="ModernClientBenchmark.Page1">
      <StackLayout>
        <Button Text="Run the test!" Clicked="OnTestClicked" x:Name="btn"></Button>
        <Label Text="here we are" x:Name="labl"/>
      </StackLayout>
    </ContentPage>
    

    第1.xaml.cs页:

    public partial class Page1 : ContentPage
    {
        private const int TESTQ = 3;
    
        public Page1()
        {
            InitializeComponent();
        }
    
        private async void OnTestClicked(object sender, EventArgs e)
        {
            btn.IsEnabled = false;
            var l1 = new double[TESTQ];
            var l2 = new double[TESTQ];
            for (int i = 0; i < TESTQ; i++)
            {
                Device.BeginInvokeOnMainThread(() => labl.Text = "Step " + i);
                l2[i] = (await ManagedNetworkSpeedAsync(true)).Milliseconds;
                //l1[i] = (await NativeNetworkSpeedAsync(true)).Milliseconds;
            }
    
            //var avg1 = l1.Sum() / TESTQ;
            //var avg2 = l2.Sum() / TESTQ;
    
            var a = 234;
    
        }
    
        public static async Task<TimeSpan> NativeNetworkSpeedAsync(bool secure)
        {
            using (var client = new HttpClient(new NativeMessageHandler()))
            {
                return await RunTestAsync(secure, client);
            }
        }
    
        public static async Task<TimeSpan> ManagedNetworkSpeedAsync(bool secure)
        {
            using (var client = new HttpClient())
            {
                return await RunTestAsync(secure, client);
            }
        }
    
        public static async Task<TimeSpan> RunTestAsync(bool secure, HttpClient client)
        {
            try
            {
    
                var start = DateTime.Now;
                for (var i = 0; i <= 1; i++)
                {
                    var result = client.GetStreamAsync(secure ? "https://xamarin.com" : "http://httpbin.org/ip").Result;
                    result.Dispose();
                }
                return DateTime.Now - start;
            }
            catch (Exception ex)
            {
                var a = 234;
            }
            return new TimeSpan();
        }
    }
    
    2 回复  |  直到 8 年前
        1
  •  1
  •   SushiHangover    8 年前

    您已经在UIThread上,并且正在阻塞自己,您需要将您的工作放在线程池中,并从那里更新UI await Task.Run 布洛克将完成这项工作。

    这将为您提供您期望的结果:

    private async void OnTestClicked(object sender, EventArgs e)
    {
        btn.IsEnabled = false;
        var l2 = new double[TESTQ];
        await Task.Run(async () => {
            for (int i = 0; i < TESTQ; i++)
            {
                Device.BeginInvokeOnMainThread(() => labl.Text = "Step " + i);
                l2[i] = (await ManagedNetworkSpeedAsync(true)).Milliseconds;
            }
        });
        foreach (var x in l2)
        {
            System.Diagnostics.Debug.WriteLine(x);
        }
        btn.IsEnabled = true;
    }
    
        2
  •  1
  •   Matías Fidemraizer    8 年前

    因为您正在启动一个异步操作,并且它正在与UI线程同步,所以在UI线程有时间执行整个更改之前,整个标签不会更改。

    这是现代应用程序的常规行为,在这种情况下,您不希望为长时间运行的操作(即异步操作,如通过HTTP请求外部资源)阻塞UI。

    顺便说一句,您可以在开始异步操作之前禁用按钮,并在完成后再次启用它。