I want to write a Win8 app, there I use a Configuration
-class with a static
member, which is loaded once at startup and can be accessed from everywhere at runtime.
So, the main problem is, the default settings are stored within an xml file, but reading file content is asynchronous (StorageFile
), but I do not find any solution to wait, until the file is completely loaded, because it is not possible to use await
in every situation (main thread, constructors), what looks to me like a design issue.
If the file isn't read completely before the Configuration
data is accessed, there will be incorrect behaviors for this app.
here is an example code:
public class Configuration
{
// stores the only instance of this class
private Configuration instance = null;
// public access to the instance
public Configuration Current
{
get
{
if (instance == null)
{
instance = new Configuration();
}
return instance;
}
}
private Configuration()
{
// load data from file synchronously
// so it is loaded once on first access
}
}
I'm not sure, how to solve this problem, probably I need to change the design of my Configuration
-class. Any suggestions/hints would be nice.
It was a design decision not to allow any synchronous calls that could take longer than 50 ms, i.e. any file or network IO calls, to make applications more responsive.
Although you can't await
asynchronous calls from a constructor, nothing is stopping you from firing such calls without waiting for them to complete:
private Configuration()
{
Init();
}
private async void Init()
{
var contents = await FileIO.ReadTextAsync(file);
}
You can then set Configuration
properties from inside Init()
. If you implement INotifyPropertyChanged
, you can bind the values to UI before they are loaded and the UI will refresh once they are.
If you need to check or wait for the operation to complete at some point in your app you can change the signature of Init()
to return Task
:
private Configuration()
{
InitTask = Init();
}
private async Task Init()
{
var contents = await FileIO.ReadTextAsync(file);
}
public Task InitTask { get; private set; }
Now you can check whether it is completed:
if (Configuration.Current.IsCompleted)
{
//
}
or even await
it (this will complete immediately if Task
has already completed):
await Configuration.Current.InitTask;
EDIT:
If it doesn't make sense to display anything to the user until the said file is loaded, you could modify your entry page to have to alternative "views":
You could make the right one visible based on IsCompleted
property which you should expose on your viewmodel with INotifyPropertyChanged
implemented.
You could then design your page as follows:
<Page xmlns:common="using:MyApp.Common">
<Page.Resources>
<common:BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</Page.Resources>
<Grid>
<Grid Visibility="{Binding Configuration.IsCompleted, Converter={StaticResource BoolToVisibilityConverter}">
<!-- put your actual view here -->
</Grid>
<Grid Visibility="{Binding Configuration.IsNotCompleted, Converter={StaticResource BoolToVisibilityConverter}">
<!-- put your splash screen view here -->
</Grid>
</Grid>
</Page>