如何在Unity中等待HoloLens 2的UWP文件选择器关闭?
HoloLens 2 Unity开发:UWP与Unity线程交互下等待FileOpenPicker完成的解决方案
我正在用Unity开发HoloLens 2应用,需要搞懂UWP环境和.NET/Unity环境的交互切换方法。现在遇到的问题是,点击按钮调用FileOpenPicker.PickSingleFileAsync()获取文件路径时,FilePicker_Hololens()方法在文件对话框还没关闭就返回了已完成的Task,导致调用StartPicker()的代码同步执行,没等到选择结果就继续走了。我猜问题出在UnityEngine.WSA.Application.InvokeOnUIThread和InvokeOnAppThread的跨线程委托调用上,请问该怎么实现等待对话框关闭后再继续执行?
代码示例
Part1:调用选择器的入口方法
调用方会通过await执行StartPicker()来获取文件名,用于后续计算
public async Task<String> StartPicker() { #if !UNITY_EDITOR && UNITY_WSA_10_0 Debug.Log("HOLOLENS 2 PICKER"); await FilePicker_Hololens(); #endif #if UNITY_EDITOR Debug.Log("UNITY_STANDALONE PICKER"); await FilePicker_Win(); #endif // 当前这里返回空字符串,因为调用的任务提前完成了 return filePath; }
Part2:HoloLens平台的文件选择实现
负责调用UWP的文件选择器,LoadDataset()是实际加载数据的方法,也需要等待选择完成后执行
#if !UNITY_EDITOR && UNITY_WSA_10_0 private async Task FilePicker_Hololens() { // UWP的文件选择器必须在UI线程执行 UnityEngine.WSA.Application.InvokeOnUIThread(async () => { var filepicker = new FileOpenPicker(); filepicker.FileTypeFilter.Add("*"); filepicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; var file = await filepicker.PickSingleFileAsync(); // 文件选择器关闭后切回Unity的App线程处理结果 UnityEngine.WSA.Application.InvokeOnAppThread(async () => { filePath = (file != null) ? file.Path : "Nothing selected"; await LoadDataset(); }, true); }, true); // 当前这里直接返回了完成态的Task,没有等待对话框操作完成 } #endif
解决方案
核心问题是InvokeOnUIThread仅异步触发委托,但不会返回可等待的Task,导致外层的FilePicker_Hololens()提前结束。我们可以用TaskCompletionSource手动控制Task的完成时机,实现等待对话框关闭及后续操作完成。
修改后的FilePicker_Hololens()代码如下:
#if !UNITY_EDITOR && UNITY_WSA_10_0 private async Task FilePicker_Hololens() { // 创建TaskCompletionSource来跟踪对话框及后续操作的完成状态 var tcs = new TaskCompletionSource<bool>(); UnityEngine.WSA.Application.InvokeOnUIThread(async () => { var filepicker = new FileOpenPicker(); filepicker.FileTypeFilter.Add("*"); filepicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary; var file = await filepicker.PickSingleFileAsync(); var selectedPath = (file != null) ? file.Path : "Nothing selected"; // 切回Unity App线程处理结果和加载逻辑 UnityEngine.WSA.Application.InvokeOnAppThread(async () => { filePath = selectedPath; await LoadDataset(); // 手动标记任务完成,让外层await继续执行 tcs.SetResult(true); }, true); }, true); // 等待直到对话框操作和数据加载都完成 await tcs.Task; } #endif
关键修改点说明
- 用
TaskCompletionSource<bool>创建一个可手动控制的Task,外层方法通过await tcs.Task等待,直到我们主动调用SetResult - 在App线程完成
LoadDataset()后再调用tcs.SetResult(true),确保所有后续逻辑执行完毕后,外层的await FilePicker_Hololens()才会继续 - 将文件路径赋值和
LoadDataset()放在同一个App线程委托中,避免跨线程数据同步问题
额外注意事项
- 确保
filePath仅在Unity App线程中访问和修改,避免多线程竞争 - 如果
LoadDataset()是耗时操作,保持其异步执行,不要阻塞线程
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

