Álvaro García
Álvaro García

Reputation: 19356

The async method is not await

In this thread, I could solve my problem to wait a async method in the constructor, using an event. In this case, the event uses a delegate without parameters.

But now I need to wait the view model finishes to wait the async method to can continue.

I have this code in my main view model:

public void printMethod()
{
    SecondViewModel mySeocViewModel = new SecondViewModel(myParameter);
    SecondView mySecondView = new SecondView();
    mySecondView.DataContext = mySeocViewModel;

    //I have to wait until it finished to can print the user control
    //The problem is that this point is reached before mySecondViewModel finish.
}

The code in my second view model:

public docFacturasViewModel(MyType parameter)
{
    this.GetDataFromDatabaseEvent += OnGetDataFromDatabase;

    GetDataFromDatabaseEvent(parameter);
}


public delegate void GetDataFromDatabaseEventHandler(MyType parameter);
public event GetDataFromDatabaseEventHandler GetDataFromDataBaseEvent;

private async void OnBuscarDatos(MyType paramter)
{
    await getDataFromDatabaseAsync(parameter);

    //Fill the data of the properties of the view model with the data from database
}


private async Task getDataFromDatabaseAsync(MyType parameter)
{
    _myResult = (await getdataAsync(parameter)).FirstOrDefault();
}

If i debug the code, it runs in this way:

I don't understand why in the second view model the code doesn't wait until get the data from the database, because I am using the await keyword and all the code is the same than in the case of the post that I link at the beggining.

Thanks.

EDIT:

If the constructor of the second view model I use this:

Task.Run(() => buscarDatosAsync(paramFacturaParaImprimir)).Wait();

Then the main view model wait until the second view model finish to get the data from database.

But when I tried this method in the first case, in the case that I linked and I asked in the other post, the method is not waited, so I don't understand why in one case I have to use a delegate and in the other case I can use a task and wait it finishes.

Upvotes: 0

Views: 440

Answers (2)

Dennis
Dennis

Reputation: 37770

Assuming, that you're writing some XAML-based code, you've got a design problem here.

Do not mix view model creation and data loading. Usually you create view models and views synchronously, and load/post data in asynchronous way. So, don't wait anything inside view model constructors.

View models and views must operate properly without any data (when data properties are nulls or empty collections). If you don't want to give access to some of commands until data is loaded, just disable these commands (return false from CanExecute).

Upvotes: 1

Camilo Terevinto
Camilo Terevinto

Reputation: 32068

When an async void method reaches an await, the control is returned to the caller. Obviously, this is not the best idea when you need the result of the operation to continue processing. Besides this, I wouldn't expect a constructor to have the side effect of creating fire-and-forget tasks.

If you need the result of the data as part of the construction of the object, I would suggest you a factory approach:

private SecondViewModel()
{
}

public static async Task<SecondViewModel> CreateAsync(MyType parameter)
{
    var result = new SecondViewModel();

    result.SomeData = await getDataFromDatabaseAsync(parameter);

    return result;
}

And you would use it like this:

public async Task printMethod()
{
    SecondViewModel mySeocViewModel = await SecondViewModel.CreateAsync(myParameter);
    SecondView mySecondView = new SecondView();
    mySecondView.DataContext = mySeocViewModel;
}

Upvotes: 4

Related Questions