Reputation: 19356
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
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 null
s 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
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