简体   繁体   中英

Order of events once UI button is pressed (C#, UWP, XAML)

Edit for up-front clarity: This needs to work in Universal Windows Platform application. Maybe it's not relevant, but things such as Thread.Start() are not available to me.

I want text blocks to update as indicated in the code below.

But text blocks only update AFTER "Btn_Click()" is finished.

How can I make this work?

private void Btn_Click()
{
     TextBlock1.Text = "Work started."
     DoWork();
     TextBlock1.Text = "Work done."
}

private void DoWork()
{
     myTextBlock2.Text = "Step 1"
     Step1();
     myTextBlock2.Text = "Step 2"
     Step2();
     myTextBlock2.Text = ""
}

This is a classic async problem.

You have to make your DoWork function asynchronous, and than call it using await. Like this.

private async void Btn_Click()
{
    TextBlock1.Text = "Work started."
    await DoWork();
    TextBlock1.Text = "Work done."
}

If you have questions about asynchronous programming, visit these documentations:

https://docs.microsoft.com/en-us/dotnet/csharp/async

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

https://docs.microsoft.com/en-us/dotnet/standard/async-in-depth

EDIT:

This is an example on how to implement an async program.

private async void Btn_Click()
{
    TextBlock1.Text = "Work started."
    await DoWork();
    TextBlock1.Text = "Work done."
}

private async Task DoWork()
{
    myTextBlock2.Text = "Requesting html from the web.";

    HttpClient _httpClient = new HttpClient();
    string data = await _httpClient.GetStringAsync("example.com/stringdata.html");
    //here the function stops executing, and doesn't continue until GetStringAsync returns a value. 
    //While this, it gives back control to the callee (AKA the UI thread, so it doesn't block it, 
    //and can process data like mouse movement, and textblock text changes.)

    myTextBlock2.Text = "Processing data";
    string outputData = await Task.Run(() => HighCPUBoundWork(data));

    //The CPU bound work doesn't block the UI thread, because we created a new thread for it.
    //When it completes, we continue.

    myTextBlock2.Text = "Writing output data to file";

    using (StreamWriter writer = File.CreateText("output.txt"))
    {
        await writer.WriteAsync(outputData);
        //Same thing applies here, we are waiting for the OS to write to the specified file, 
        //and while it is doing that, we can get back to the UI.
    }
}

private string HighCPUBoundWork(string data)
{
    //Here you can do some high cpu intensity work, like computing PI to the 1000000000th digit, or anything.
    //The html files processing would be more likely tho.. :)
    //Notice, that this function is not async.

    return modifiedInputData;
}

What you need to do is to use Async by make Thread-Safe Calls in Windows Forms Controls. This is also a good example by Microsft Example

Try this code:

 private async void button1_Click_1(object sender, EventArgs e)
    {
        button1.Text = "Work started.";
        Task myTask = new Task(DoWork);
        myTask.Start();
        await myTask;
        button1.Text = "Work done.";
    }

 private void DoWork()
    {
        this.SetMessageText("Step 1");
        Thread.Sleep(2000); // --> you can replace it with your actual method
        this.SetMessageText("Step 2");
        Thread.Sleep(2000); // --> you can replace it with your actual method
        this.SetMessageText(" ");
    }

This delegate enables asynchronous calls for setting the text property on a TextBox control.

delegate void StringArgReturningVoidDelegate(string text); 

This method demonstrates a pattern for making thread-safe calls on a Windows Forms control.

If the calling thread is different from the thread that created the TextBox control, this method creates a StringArgReturningVoidDelegate and calls itself asynchronously using the Invoke method.

If the calling thread is the same as the thread that created the TextBox control, the Text property is set directly.

private void SetMessageText(string text)
    {
        // InvokeRequired required compares the thread ID of the  
        // calling thread to the thread ID of the creating thread.  
        // If these threads are different, it returns true.  
        if (this.label1.InvokeRequired)
        {
            StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetMessageText);
            this.Invoke(d, new object[] { text });
        }
        else
        {
            this.label1.Text = text;
        }
    }

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