多次异步调用UI线程以更新文本块

本文关键字:更新 文本 线程 UI 异步 调用 | 更新日期: 2023-09-27 18:29:15

我正在为我的游戏编写战斗机生成页面。该页面应该在从服务器下载战斗机时,使用强度和其他属性的随机化值更新UI。

到目前为止的代码:

    public partial class FighterGenerationPage : PhoneApplicationPage
{
    Fighter fighter = null;
    string Code = "";
    BackgroundWorker worker;
    public FighterGenerationPage()
    {
        InitializeComponent();
        Loaded += new RoutedEventHandler(FighterGenerationPage_Loaded);
        worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
    }
    void FighterGenerationPage_Loaded(object sender, RoutedEventArgs e)
    {
        AddFighter();
    }
    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        NavigationContext.QueryString.TryGetValue("code", out Code);
        if ("".Equals(Code))
            if (NavigationService.CanGoBack)
                NavigationService.GoBack();
        base.OnNavigatedTo(e);
    }
    private void AddFighter()
    {
        WebProxy.GetInstance().AddFighter(AddFighter_Handler, Code);
        worker.RunWorkerAsync();
    }
    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        Random rand = new Random();
        while (fighter == null)
        {
            int strength = rand.Next(100);
            Dispatcher.BeginInvoke(() => { StrValue.Text = Convert.ToString(strength); });
            Thread.Sleep(100);
        }
        Dispatcher.BeginInvoke(() => { StrValue.Text = Convert.ToString(fighter.Strength); });
    }
    public void AddFighter_Handler(Response response)
    {
        #if DEBUG
        Thread.Sleep(3000);
        #endif
        if (response.Status.Error == false)
        {
            fighter = response.Fighter;
        }
    }
}

这段代码几乎做到了我想要的,但它不是每0.1秒更新一次UI,而是在开始时更新一次,然后在将其设置为最终值(fighter.Strength)之前更新多次。

为什么会有这种行为?

多次异步调用UI线程以更新文本块

我认为正在发生的事情是:

  1. 您正在Debug中运行,这意味着AddFighter_Handler()中的Thread.Sleep代码将被执行。

  2. AddFighter的电话很快就回来了。

  3. 当您在AddFighterHandler中执行Thread.Sleep()时,实际上是在阻塞用户线程,因此从未实际调用传递到BeginInvoke的代码。

下面是你能做的最简单的事情来解决这个问题:

public void AddFighter_Handler(Response response)
{
    System.Threading.ThreadPool.QueueUserWorkItem(o => {
    #if DEBUG
    Thread.Sleep(3000);
    #endif
    if (response.Status.Error == false)
    {
        fighter = response.Fighter;
    }});
}

这将确保您不会阻塞线程。

这可能也不是正确的做法——考虑使用DispatcherTimer来获得类似于您试图实现的暂停。。