2017-10-07 7 views
0

Je voulais créer un code de pratique simple dans UWP qui ouvre un fichier texte, puis ajoute immédiatement ce code avec du texte trivial.Comment j'attends la méthode async dans UWP pour FileOpenPicker?

public MainPage() 
{ 
    this.InitializeComponent(); 

    OpenFile(); 
    SaveFile(); 
} 

public async void OpenFile() 
{ 
    FileOpenPicker picker = new FileOpenPicker(); 
    picker.SuggestedStartLocation = PickerLocationId.Desktop; 
    picker.FileTypeFilter.Add(".txt"); 

    DataFile = await picker.PickSingleFileAsync(); 
    if (DataFile == null) { return; } 
} 

public async void SaveFile() 
{ 
    await FileIO.AppendTextAsync(DataFile, "" + DateTime.Now + "\n"); 
} 

private StorageFile DataFile { get; set; } 

Comme prévu, ce code renvoie une erreur car la méthode SaveFile(), puisque SaveFile() fonctionne immédiatement après OpenFile() et depuis OpenFile() n'a pas terminé son opération de récupération du fichier cible pour SaveFile () utiliser. La chose est, lorsque je tente de modifier le code suivant dans OpenFile, je reçois une erreur AggregateException:

DataFile = picker.PickSingleFileAsync(); 
Task task = Task.Run(async() => DataFile = await picker.PickSingleFileAsync()); 
task.Wait(); 

Je me demandais comment je peux bloquer OpenFile() jusqu'à ce qu'il soit fait récupérer le fichier cible, avant SaveFile () fonctionne.

+0

Cela peut être résolu par les réponses à cette question: https://stackoverflow.com/questions/32084943/async-lock-not-allowed – Laith

+0

async compose mal, c'est tortues tout le chemin et le problème de base ici est la tortue finale, le constructeur ne peut pas être asynchrone. Vous avez juste besoin de faire cela en sens inverse, * d'abord * demander un nom de fichier, * puis * créer l'objet de classe. Que son nom est MainPage n'est pas génial, ne jamais demander l'entrée de l'utilisateur immédiatement au démarrage du programme avant de montrer une interface utilisateur. Les dialogues ont besoin d'une fenêtre pour rester dessus. Sinon, la raison pour laquelle les programmes ont généralement une commande Fichier> Ouvrir. –

Répondre

2

Le constructeur d'une classe devrait être rapide et ne devrait certainement pas avoir de méthodes async. Dans votre cas, vous avez tiré ces méthodes comme fire-forget, il y a une condition de concurrence, où vous n'avez pas choisi un fichier et vous essayez d'enregistrer. Rien de bon ne vient de ça.

Au lieu de cela, si vous voulez un utilisateur de faire soemthing une fois que votre MainPage est créé, vous pouvez par exemple utiliser l'événement Loaded pour cela:

public MainPage() 
{ 
    this.InitializeComponent(); 
    this.Loaded += LoadedHandler; 
} 

private async void LoadedHandler(object sender, RoutedEventArgs e) 
{ 
    // assume that we want to do this only once 
    this.Loaded -= LoadedHandler; 
    await OpenFile(); 
    await SaveFile(); 
} 

public async Task OpenFile() 
{ 
    FileOpenPicker picker = new FileOpenPicker(); 
    picker.SuggestedStartLocation = PickerLocationId.Desktop; 
    picker.FileTypeFilter.Add(".txt"); 

    DataFile = await picker.PickSingleFileAsync(); 
    if (DataFile == null) { return; } 
} 

public async Task SaveFile() 
{ 
    await FileIO.AppendTextAsync(DataFile, "" + DateTime.Now + "\n"); 
} 

private StorageFile DataFile { get; set; } 

Notez également que j'ai changé vos méthodes pour tâches - vous devriez avoid async void.

+1

La conversion en 'Task' ne sert pas à elle-même ... vous n'avez pas les appels dans un' try/catch' et l'appelant (le gestionnaire d'évènement) est 'void' donc les exceptions vont encore s'échapper dans' Exceptions non observées. –

+0

@ PeterTorr-MSFT Vous avez raison dans ce cas. Le lien fourni après l'édition, devrait donner un peu de lumière au lecteur. J'ai ajouté ceci pour mentionner d'éventuels problèmes. – Romasz