Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update text box on continuation with Winforms and C#

C# noob here, coming from experience in other languages. (Most notably Java).

I'm looking at this question's code. It's a standard WinForms C# project in VS 2013:

drop a button and a textbox on the form and use this code:

private void button1_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
        .ContinueWith(t => DelayedAdd(t.Result, 20))
        .ContinueWith(t => DelayedAdd(t.Result, 30))
        .ContinueWith(t => DelayedAdd(t.Result, 50))
        .ContinueWith(t => textBox1.Text = t.Result.ToString(),
            TaskScheduler.FromCurrentSynchronizationContext());
}

private int DelayedAdd(int a, int b)
{
    Thread.Sleep(500);
    return a + b;
}

Press the button, wait 2 seconds for the four DelayedAdd calls to complete, and the result (115) is displayed in the text box. How can I get the result displayed on the text box after every DelayedAdd call?

I tried to shove the final continuation between each call,

Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
    .ContinueWith(t => textBox1.Text = t.Result.ToString(),
        TaskScheduler.FromCurrentSynchronizationContext())

    .ContinueWith(t => DelayedAdd(t.Result, 20))
    .ContinueWith(t => textBox1.Text = t.Result.ToString(),
        TaskScheduler.FromCurrentSynchronizationContext())

    .ContinueWith(t => DelayedAdd(t.Result, 30))
    .ContinueWith(t => textBox1.Text = t.Result.ToString(),
        TaskScheduler.FromCurrentSynchronizationContext())

    .ContinueWith(t => DelayedAdd(t.Result, 50))
    .ContinueWith(t => textBox1.Text = t.Result.ToString(),
        TaskScheduler.FromCurrentSynchronizationContext());

but that fails, I'm guessing because the continuations I inserted don't return the integer result t. I'm such a C# noob that I don't even know how to fix that, let alone do this in an idiomatic way.

like image 793
kdbanman Avatar asked Jun 25 '15 19:06

kdbanman


2 Answers

I'd just change DelayedAdd method:

    private void button1_Click(object sender, EventArgs e)
    {
        Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
            .ContinueWith(t => DelayedAdd(t.Result, 20))
            .ContinueWith(t => DelayedAdd(t.Result, 30))
            .ContinueWith(t => DelayedAdd(t.Result, 50));
    }

    private int DelayedAdd(int a, int b)
    {
        if (textBox1.InvokeRequired)
        {
            textBox1.BeginInvoke((Action)(() => textBox1.Text = (a + b).ToString()));
        }
        Thread.Sleep(500);
        return a + b;
    }
like image 62
voytek Avatar answered Nov 15 '22 18:11

voytek


Got it! If anyone has better/more interesting alternatives, please answer.

First I tried a multiline lambda in place of the erroneous continuations from my question:

    .ContinueWith(t => {
        textBox1.Text = t.Result.ToString();
        return t.Result;
    },
        TaskScheduler.FromCurrentSynchronizationContext()); 
    }

That's a tad verbose and repetitive, so I DRYed it up:

    private void button1_Click(object sender, EventArgs e)
    {
        // SCHEDULING LOGIC
        Task.Factory.StartNew<int>(() => DelayedAdd(5, 10))
            .ContinueWith(t => UpdateText(t.Result),
                TaskScheduler.FromCurrentSynchronizationContext())

            .ContinueWith(t => DelayedAdd(t.Result, 20))
            .ContinueWith(t => UpdateText(t.Result),
                TaskScheduler.FromCurrentSynchronizationContext())

            .ContinueWith(t => DelayedAdd(t.Result, 30))
            .ContinueWith(t => UpdateText(t.Result),
                TaskScheduler.FromCurrentSynchronizationContext())

            .ContinueWith(t => DelayedAdd(t.Result, 50))
            .ContinueWith(t => UpdateText(t.Result),
                TaskScheduler.FromCurrentSynchronizationContext()); 
    }

    private int UpdateText(int i)
    {
        // UI LOGIC
        textBox1.Text = i.ToString();
        return i;
    }

    private int DelayedAdd(int a, int b)
    {
        // PROCESS LOGIC
        Thread.Sleep(500);
        return a + b;
    }
like image 24
kdbanman Avatar answered Nov 15 '22 18:11

kdbanman