简体   繁体   中英

Multiple async calls to UI thread to update textblock

I'm writing a fighter generation page for my game. The page is supposed to update the UI with randomized values for strength and other attributes while the fighter is being downloaded from the server.

Code so far:

    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;
        }
    }
}

This code does almost do what I want, but instead of updating the UI every 0.1 sec it does it one time at start and then many times just before it sets it to the final value (fighter.Strength).

Why this behavior?

What I think is happening is this:

  1. You are running in Debug, which means that your Thread.Sleep code in AddFighter_Handler() gets executed.

  2. The call to AddFighter comes back very quickly.

  3. When you Thread.Sleep() in AddFighterHandler, you are actually blocking the user thread, thus never actually calling the code you pass into BeginInvoke.

Here's the simplest thing you can do to solve this:

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;
    }});
}

This will make sure you do not block the thread.

It's also probably not the right thing to - consider using the DispatcherTimer to get something like that pause you are trying to achieve..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM