-1

I want to check if a TextBox is empty and then give a error warning to the user using a MessageDialog. My problem is that the async method needs a void return type so I cannot use a bool to check is CheckEmpty returns a true or false. How can I stop the code in AddButton_Click after CheckEmpty() when this gives an error/message warning?

public void AddButton_Click(object sender, RoutedEventArgs e)
    {
        if (roleComboBox.SelectionBoxItem.Equals("Player"))
        {
            CheckEmpty();
            memberID++;

            Player player = new Player(memberID, team, firstName, lastName, age, salary, yearsActive, position, minutesPerGame);

            players.Add(player);

            idBox = idComboBox;
            idBox.Items.Add(memberID);

            PrintList();
        }
    }


private async void CheckEmpty()
    {
        if (firstNameTextBox.Text == "") //if (String.IsNullOrEmpty(firstNameTextBox.Text) 
        {
            var messageDialog = new MessageDialog("Text here");
            messageDialog.Commands.Add(new UICommand("Try again"));
            await messageDialog.ShowAsync();
        }
Danny Roulaux
  • 57
  • 1
  • 7
  • 3
    Why `CheckEmpty()` needs to be `Void` ? – HMZ Jul 16 '20 at 12:27
  • "async void" Never do this, well 99.9% of the time, FYI. https://stackoverflow.com/questions/12144077/async-await-when-to-return-a-task-vs-void/23016998#23016998 – granadaCoder Jul 16 '20 at 12:33
  • 1
    @granadaCoder Telling someone to never do something when *the code they presented merits doing it* isn't a very good idea. You even did the thing you said should never be done *in your answer to the question*. – Servy Jul 16 '20 at 12:49
  • https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async#example – granadaCoder Jul 16 '20 at 17:02
  • 1
    So I mimicked the microsoft example (because if you only leave a link, that is not a best practice on SOF). the microsoft example has "private async void StartButton_Click(object sender, RoutedEventArgs e)" but the same ms article has "void. async void methods are generally discouraged for code other than event handlers because callers cannot await those methods and must implement a different mechanism to report successful completion or error conditions." i upvoted the JB answer..but i gave an answer that is germane to the question and that closely follows the ms example. link in prev comment – granadaCoder Jul 16 '20 at 17:08

3 Answers3

3

CheckEmpty can return a Task<bool>, and to comply with conventions should be renamed to CheckEmptyAsync:

private async Task<bool> CheckEmptyAsync()
{
    if (firstNameTextBox.Text == "") //if (String.IsNullOrEmpty(firstNameTextBox.Text) 
    {
        var messageDialog = new MessageDialog("Text here");
        messageDialog.Commands.Add(new UICommand("Try again"));
        await messageDialog.ShowAsync();

        return true;
    }

    return false;
}

Then you can check that in your AddButton_Click method by making it async:

public async void AddButton_Click(object sender, RoutedEventArgs e)
{
    if (roleComboBox.SelectionBoxItem.Equals("Player"))
    {
        if (await CheckEmptyAsync())
        {
            return;
        }

        // ...
    }
}

Alternatively, this is one situation where there is no real harm in discarding the Task returned by ShowAsync and running the code synchronously:

private bool CheckEmpty()
{
    if (firstNameTextBox.Text == "") //if (String.IsNullOrEmpty(firstNameTextBox.Text) 
    {
        var messageDialog = new MessageDialog("Text here");
        messageDialog.Commands.Add(new UICommand("Try again"));
        _ = messageDialog.ShowAsync();

        return true;
    }

    return false;
}
Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
  • I dont understand the line: _ = messageDialog.ShowAsync(); could you elaborate? – Danny Roulaux Jul 16 '20 at 14:53
  • 1
    @DannyRoulaux `_` is a [discard](https://learn.microsoft.com/en-us/dotnet/csharp/discards), which was introduced in C#7, and makes explicit that you are ignoring the value (i.e. `Task`) returned by `messageDialog.ShowAsync()`. The code would compile, and work identically, without the discard, but it indicates that you have made the conscious decision not to await the `Task`'s completion. – Johnathan Barclay Jul 16 '20 at 15:00
  • Thx, didnt know about discards. Also thanks for the link, gonna study it now. – Danny Roulaux Jul 16 '20 at 15:27
1

The easiest solution would be to use async Task, this allows your asynchronous method to return a value

        private async Task<bool> CheckEmptyAsync()
        {
            //its also good practice to put the constants on the left hand side 
            if (string.Empty == firstNameTextBox.Text)
            {
                await (new MessageDialog("Text here")).Commands.Add(new UICommand("Try again"))).ShowAsync();
                return true;
            }
            return false;
        }
0

You can return a Task.

if your code (the "checker") throws an exception, you don't need a Task<bool>. Its a little bit of a gray area decision Task<bool> vs Task.

But here is Task only alternative.

You can see a similar example here: (this one is Task<int> for a third option!)

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/async#example

private async Task CheckEmpty()
{
    if (firstNameTextBox.Text == "") //if (String.IsNullOrEmpty(firstNameTextBox.Text) 
    {
      throw ArgumentNullException("blah blah blah");

    }


}





public async void AddButton_Click(object sender, RoutedEventArgs e)
{
    try {

    if (roleComboBox.SelectionBoxItem.Equals("Player"))
    {
        await CheckEmpty();

           /* other stuff */
    }
    }
    catch (Exception ex)
    {
        /* alert user here, without crashing the system */

        var messageDialog = new MessageDialog(ex.Message);
        messageDialog.Commands.Add(new UICommand("Try again"));
        await messageDialog.ShowAsync();

    }
}

Note the MS article example has

private async void StartButton_Click(object sender, RoutedEventArgs e)

but as the same time has this (contradictory) suggestion:

void. async void methods are generally discouraged for code other than event handlers because callers cannot await those methods and must implement a different mechanism to report successful completion or error conditions.

but they provide this hint:

You use the void return type primarily to define event handlers, which require that return type. The caller of a void-returning async method can't await it and can't catch exceptions that the method throws.

So the MS article explains why there is a discrepancy between the code they how, vs the not-best-practice suggestion.

Philosophically, you can read this

https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/exception-throwing

namely:

" DO report execution failures by throwing exceptions."

granadaCoder
  • 26,328
  • 10
  • 113
  • 146