Reputation: 29
I have a page (Mainpage) and SQLite database. I need to reed SQLite database first, then Update my page controls.
This is my page code:
public MainPage()
{
this.InitializeComponent();
// Get SQLite and language setting
SQLiteData();
// Update controls in page
GetConnectionList();
}
This is the code of SQLiteData() :
public async void SQLiteData()
{
conn = new SQLiteAsyncConnection("Setting.db");
await conn.CreateTableAsync<SettingTable>();
await conn.CreateTableAsync<DataPlanTable>();
....
}
because I use 'await' in SQLiteData(), debugger go to run GetConnectionList() without finishing and get data from SQLite so I get error in my app.
How Can I solve that? Is it possible to help me?
Thanks.
Upvotes: 1
Views: 380
Reputation: 16767
The key is that you declared SQLiteData as async, but in your MainPage constructor you have not 'waited' for the SQLiteData task to complete.
You should await for SQLiteData to complete, BUT you cannot do that easily inside of the constructor... and nor should you. Can constructors be async?
Please move time consuming and async tasks out of the constructor and into other methods in your class, a key reason is so that you can implement some better error handling routines and you could re-execute the connection logic if the connection fails the first time.
public async InitialiseDataConnections()
{
// Get SQLite and language setting
await SQLiteData();
// Update controls in page
GetConnectionList();
}
Now you have a single purpose method that you could call from the constructor... but a better solution would be to call this from the OnNavigatedTo event handler on your page class.
It is a general expectation in programming that creating an instance of an object should be relatively lightweight compared to the execution of actions against the object. Here's an interesting discussion: How much work should be done in a constructor
In universal apps it is expected that lightweight configuration is handled in the constructor and the bulk of initialisation 'logic' is delayed until the page is actually navigated to (OnNavigatedTo). Especially when we consider data access scenarios it might be important for the data to be as up-to-date as possible but there is another important event, when navigation to the page has resulted as backward navigation or after the application has been resumed. In these events you may be able to obtain some state or configuration from a previous serialised state, rather than re-initialising everything which could be a time consuming process.
So the 'best practises' here is to use OnNavigatedTo to process any page initialisation other than creation of page controls. You have access to the NavigationEventArgs that will help you to re-create the page in the state that the user is expecting. It is where other developers will look first to review the business logic behind your page, AND you can declare the OnNavigatedTo handler as async!
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
await InitialiseDataConnections();
}
Upvotes: 1
Reputation: 1294
One way to do this is to move the asynchronous initialization out of your ctor in OnNavigatedTo. However, you must realize that OnNavigatedTo will return control to the framework before its asynchronous part will complete. That is probably OK but you need to consider how you handle errors.
I would structure this code a little bit differently though:
...
// The UI will use data binding to PageState to show
// UI specific for the initialization phase.
public PageState PageState {get; private set {.../*include property change notification */...};}
// The UI will use data binding to ErrorMessage as needed.
public string ErrorMessage {get; private set {.../*include property change notification */...};}
...
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
await InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
// Have the UI bind to
PageState = PageState.InitializingInProgress;
await SQLiteData();
GetConnectionList();
...
PageState = PageState.InitializedOk;
}
catch(...)
{
PageState = PageState.InitializedWithError;
ErrorMessage = ...
}
}
}
Upvotes: 0