英文:
How to await UWP Filepicker for Hololens 2 in Unity
问题
我正在为HoloLens 2使用Unity开发应用程序。我需要一些帮助理解如何在UWP环境和.NET/Unity环境之间进行通信和跳转。
我试图在按钮按下后使用FileOpenPicker的PickSingleFileAsync()函数来获取所选文件的路径,就像这个帖子中所述,我有类似的情景:
代码:
部分1:
一个方法调用StartPicker()来获取文件名,然后进行后续计算。但是这个方法等待结果 => 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
//等待Picker返回路径
//注意:目前返回空字符串,因为调用方法似乎已经完成任务
return filePath;
}
部分2: 该方法应指示文件对话框是否已完成,因此已获取路径(LoadDataset() 负责实际加载,如果路径可用,则应在此等待)。
#if !UNITY_EDITOR && UNITY_WSA_10_0
private async Task FilePicker_Hololens()
{
//必须在UI线程上调用UWP。
UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
{
var filepicker = new FileOpenPicker();
filepicker.FileTypeFilter.Add("*");
filepicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
var file = await filepicker.PickSingleFileAsync();
//注意:在文件选择器关闭后调用
UnityEngine.WSA.Application.InvokeOnAppThread(async () =>
{
filePath = (file != null) ? file.Path : "未选择任何文件";
await LoadDataset();
}, true);
}, true);
//在这里我们应该能够返回一个已完成的任务
}
#endif
问题:
我的问题是,似乎FilePicker_Hololens()即使文件对话框未完成也返回已完成的任务,因此未获取路径。我等待执行StartPicker()以及内部执行FilePicker_Hololens。尽管如此,调用StartPicker()的调用方同步执行其余方法,不会在await处离开方法。我认为问题出在UnityEngine.WSA.Application.InvokeOnUIThread
和UnityEngine.WSA.Application.InvokeOnAppThread
之间的UWP和Unity上下文之间的跳转。
如何等待对话框关闭?
英文:
I am developing an application for the HoloLens 2 with Unity. I need some help understanding how to communicate and jump between the UWP environment and the .NET/Unity environment.
I am trying to use the FileOpenPicker with the PickSingleFileAsync() function after a button press to get the path of a selected file. Like in this Post i have kind of this scenario:
Code:
Part1:
A method calls StartPicker() to get a file name with which subsequent calculations happen. But this method waits for the result => 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
//Wait for Picker retrieve path
// Note: Currently returns empty string as calling method has Task seems to be finished
return filePath;
}
Part 2: Method which should indicate if FileDialog is finished and therefore path is obtained. (LoadDataset() takes care of the actual loading if the path is available and should be waited for here too).)
#if !UNITY_EDITOR && UNITY_WSA_10_0
private async Task FilePicker_Hololens()
{
// Calls to UWP must be made on the UI thread.
UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
{
var filepicker = new FileOpenPicker();
filepicker.FileTypeFilter.Add("*");
filepicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
var file = await filepicker.PickSingleFileAsync();
//Note: Called after the file picker is closed
UnityEngine.WSA.Application.InvokeOnAppThread(async () =>
{
filePath = (file != null) ? file.Path : "Nothing selected";
await LoadDataset();
}, true);
}, true);
// Here we should be able to return a finished Task
}
#endif
Problem:
My problem is now that it seems FilePicker_Hololens() returns a finished Task even if the FileDialog is not finished, hence no path is acquired. I await the execution StartPicker() as well as the execution of FilePicker_Hololens inside. Nevertheless, the caller of StartPicker() executes its remaining method synchronously and does not leave the method at await. I think my Problems lies in the jumping between UWP and Unity Context with UnityEngine.WSA.Application.InvokeOnUIThread
and UnityEngine.WSA.Application.InvokeOnAppThread
due to the delegates.
How can i await the closing of the dialog?
答案1
得分: 1
Your FilePicker_Hololens
函数确实会立即返回,因为你只是将其余的操作安排在下一个UIThread运行中,但没有等待它实际发生。
你可以使用一个TaskCompletionSource
来实现,例如:
private async Task FilePicker_Hololens()
{
var completionSource = new TaskCompletionSource<object>();
UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
{
var filepicker = new FileOpenPicker();
filepicker.FileTypeFilter.Add("*");
filepicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
var file = await filepicker.PickSingleFileAsync();
UnityEngine.WSA.Application.InvokeOnAppThread(async () =>
{
filePath = (file != null) ? file.Path : "Nothing selected";
// 应该在这里执行吗?
await LoadDataset();
// 设置完成源任务为已完成
completionSource.SetResult(null);
}, true);
}, true);
// 使此任务等待,直到完成源通过调用`SetResult`等完成
await completionSource.Task;
}
通常,不必通过字段来访问filePath
,你实际上可以直接将其作为Task<string>
,并相应地使用TaskCompletionSource<string>
,然后传入SetResult(filePath)
。然后在StartPicker
中,你可以实际上执行:
return await FilePicker_Hololens();
英文:
Your FilePicker_Hololens
indeed returns immediately since you only schedule all the rest to happen in the next UIThread run but do not wait for this to actually have happened.
You could use a TaskCompletionSource
and do e.g.
private async Task FilePicker_Hololens()
{
var completionSource = new TaskCompletionSource();
UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
{
var filepicker = new FileOpenPicker();
filepicker.FileTypeFilter.Add("*");
filepicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
var file = await filepicker.PickSingleFileAsync();
UnityEngine.WSA.Application.InvokeOnAppThread(async () =>
{
filePath = (file != null) ? file.Path : "Nothing selected";
// should this happen in here at all?
await LoadDataset();
// sets the completion source task to finished
completionSource.SetResult();
}, true);
}, true);
// keeps this task awaiting until the completion source finished by e.g. calling `SetResult`
await completionSource.Task;
}
In general instead of going through fields for filePath
you could actually rather directly make this also a Task<string>
and use a TaskCompletionSource<string>
accordingly and then pass in SetResult(filePath)
. Then in StartPicker
you could actually do
return await FilePicker_Hololens();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论