#vb.net #uwp #windows-10-universal
#vb.net #uwp #windows-10-универсальный
Вопрос:
Я пытаюсь научиться писать универсальные приложения, и я начинаю с попытки воссоздать другой проект, который я написал в WinForms. Мне нужно иметь возможность читать файлы журналов в произвольной папке, и, насколько я понимаю, мне нужно получить разрешения пользователей на доступ к папке. Затем я должен сохранить токен доступа, чтобы в будущем я мог перечитывать эту папку. Читая, мне удалось собрать следующий код:
Friend Async Function GetLogFolder() As Task(Of StorageFolder)
Dim myLogFolder As StorageFolder
If ApplicationData.Current.LocalSettings.Values.ContainsKey("LogFolder") Then
Dim sToken As String = ApplicationData.Current.LocalSettings.Values("LogFolder")
myLogFolder = StorageApplicationPermissions.FutureAccessList.GetFileAsync(sToken)
Else
Dim myFolderPicker As FolderPicker = New FolderPicker
myFolderPicker.FileTypeFilter.Add("*")
myLogFolder = Await myFolderPicker.PickSingleFolderAsync
Dim sToken As String = StorageApplicationPermissions.FutureAccessList.Add(myLogFolder)
ApplicationData.Current.LocalSettings.Values.Add("LogFolder", sToken)
End If
Return myLogFolder
End Function
Но, похоже, это не работает. На данном этапе у меня есть форма, содержащая только текстовый блок и кнопку. Нажатие кнопки вызывает метод, который проанализирует все файлы * .log в данной папке. Первое, что он делает, это:
Dim myFolder As StorageFolder = GetLogFolder.Result
Когда код запускается, и я нажимаю кнопку, я получаю диалоговое окно браузера папок, но затем все зависает, и я должен переключиться на Visual Studio и нажать стоп. Вероятно, я допустил какую-то глупую ошибку, но я не могу понять, что это такое.
Любая помощь была бы очень признательна.
Ответ №1:
Проблема, скорее всего, вызвана не самим кодом доступа к файлам, а тем, как вы используете асинхронный API.
Поскольку GetLogFolder
метод возвращает Task
значение of StorageFolder
, вам нужно будет дождаться результата, а не получать его с помощью Result
свойства. Причина в том, что async/await
шаблон позволяет выполнять операции ввода-вывода в отдельном потоке, но по завершении возвращает управление обратно в поток пользовательского интерфейса. Что вы здесь делаете, так это вызываете GetLogFolder
метод, в котором вы позволяете пользователю выбирать папку, используя FolderPicker
. Вот в чем проблема — пользователю предоставляется средство выбора папок, в то время как элемент управления возвращается к вашему коду, и вы запрашиваете Result
свойство Task
, возвращаемое GetLogFolder
методом. Запрос Result
свойства приводит к остановке потока пользовательского интерфейса и ожиданию Task
завершения, чтобы получить результат. К сожалению, когда пользователь выбирает папку, элемент управления хочет вернуться в поток пользовательского интерфейса, чтобы продолжить выполнение остальной части GetLogFolder
метода, и мы имеем тупик. Result
свойство остановило поток пользовательского интерфейса, чтобы дождаться Task
результата, и Task
ожидает, пока поток пользовательского интерфейса станет доступным. Ни один из них не может продолжаться, поэтому приложение полностью зависает.
Решение довольно простое — использование async
await
ключевых слов / . Вы можете прочитать больше о них в VB.NET вот с наглядным примером.
В вашем случае первым шагом было бы создать Click
метод обработчика кнопки async
, а затем заменить код внутри следующим образом:
Dim myFolder As StorageFolder = Await GetLogFolder