0

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?

Alex
  • 151
  • 10

1 Answers1

1

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();
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • Thank you you have helped me incredibly!! I didn't know that TaskCompletionSource can be used and set by myself. But why is there the possibility to set a bool waitUntilDone in the InvokeOn methods. I thought that these set (and forward) the task for me (and therefore wait). – Alex Mar 09 '23 at 14:00
  • @Alex I have no clue tbh ^^ but of it is void then either it returns immediately or freezes .. there is no other way in c# to make it "wait" so no idea what that refers to tbh – derHugo Mar 09 '23 at 14:37