What is the best way to await a user response in the latest C# code?

Viewed 15

Although the following question has been partly answered a number of times over the past decade, C# has changed significantly in the past few years to include better constructs for handling events, tasks, and the like. What is the current best suggested way to convert the following procedural code into code appropriate for a form, i.e., code to avoid busy waiting and keeping the computer responsive? Please provide complete code. I have found that mere suggestions usually require a lot more follow up for full understanding.

The form consists of a textbox (NameBox) where the name is displayed and two buttons (ButtonM and ButtonF) labeled "Male" and "Female" which when pressed do the functions described below. I've left out any declaration of the buttons since their definition is part of the solution I hope you can provide.

    public class Question
    {
        static string[] names = {"Steve", "Lois", "Doug"};
        static char[] genders = new char[names.Length];

        public static void GetGenders (string[] names)
        {
            // Something 1
            for (int i = 0; i < names.Length; i+) {
                NameBox.Text = names[i];
                // Wait for user to press Male or Female button;
                // if (ButtonM pressed)  genders[i] = 'M';
                // if (ButtonF pressed)  genders[i] = 'F';
            }
            // Something 2
        }
    }

Thanks for your time and effort.

1 Answers

I wasn't very clear on what I was asking. Below is the code I would have used 4 years ago. My question is "Is there a better way using the current C# language to accomplish this?"

    public partial class Form1 : Form
    {
        static string[] names = {"Steve", "Lois", "Doug"};
        static char[] genders = new char[names.Length];
        public static char ch;

        public Form1 () 
        { 
            InitializeComponent(); 
        }

        private void ShownForm (object sender, EventArgs e)
        { 
            GetGenders(names);
        }

        private TaskCompletionSource<bool> clickWaitTask;

        public async void GetGenders (string[] names)
        {
            // Something 1
            for (int i = 0; i < names.Length; i++) {
                // Create a new TCS so that each time this logic is run,
                // it will wait for the click to occur.
                clickWaitTask = new TaskCompletionSource<bool>();
                textBoxName.Text = names[i];
                Application.DoEvents();
                // Wait for user to press Male or Female button;
                await clickWaitTask.Task;
                textBoxResult.Text = ch.ToString();
            }
            // Something 2
            Application.Exit();
        }

        // This task will only complete when TrySetResult is called
        // on the TCS object.
        private void ButtonClick (object sender, EventArgs e)
        {
            ch = (sender == buttonMale ? 'M' : 'F');
            clickWaitTask.TrySetResult(true);
        }
    }
}

I am unhappy with having to create and remove a task for every iteration of the loop. Without involving a third task in the loop, is there a simpler way to just block the looping thread until another thread (the one with the button) can unblock it?

Related