Search code examples
c#unity-game-enginehololensmrtkfileopenpicker

System.Exception getting called when assessing OpenFilePicker on Hololens


I'm using the MRTK for a hololens app and I need to select a file that the user puts in their document folder. I am trying to access the FileOpenPicker and use the PickSingleFileAsync() function from a button press to get the file and then load that into my app.

The code inside this function is basically what I am doing:

(Code Source)

private async void PickAFileButton_Click(object sender, RoutedEventArgs e)
        {
            // Clear previous returned file name, if it exists, between iterations of this scenario
            OutputTextBlock.Text = "";

            FileOpenPicker openPicker = new FileOpenPicker();
            openPicker.ViewMode = PickerViewMode.Thumbnail;
            openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
            openPicker.FileTypeFilter.Add(".jpg");
            openPicker.FileTypeFilter.Add(".jpeg");
            openPicker.FileTypeFilter.Add(".png");
            StorageFile file = await openPicker.PickSingleFileAsync();
            if (file != null)
            {
                // Application now has read/write access to the picked file
                OutputTextBlock.Text = "Picked photo: " + file.Name;
            }
            else
            {
                OutputTextBlock.Text = "Operation cancelled.";
            }
        }

However, when I build and deploy to the Hololens Emulator, when I press the button It runs through the first part of the code just fine but I get an exception on this line

StorageFile file = await openPicker.PickSingleFileAsync();

After extensive research and some frustration I made a very poor and vague post about it here.

In that post I referenced this post which was made 2 years ago and says you can't do this but The Microsoft docs for Hololens say that you can use File pickers, in this case, FileOpenPicker.

I found this post buried in the Windows Mixed Reality Developer Forum that's related but isn't the issue I am having, I still felt it was necessary to include in this post.

I also want to add that I do have a file picker app installed. According to this post on Microsoft Docs if you call FileOpenPicker it will open whatever file picker was first installed on your device.

Also in the MRTK and the Appx that is being generated I am ensuring the permission to "PictureLibrary" capability is enabled.

Any help would be greatly appreciated, I feel I've waited too long to make a more formal post on this topic and I'm hoping to have some answers. Thanks!


Solution

  • ALL THANKS TO THIS POST! I finally found a solution to my issue. The biggest call that wasn't mentioned in any docs I looked through was this UnityEngine.WSA.Application.InvokeOnUIThread()

    I didn't run into this, nor did I find any documentation on this being a solution for MRTK+unity for hololens development. So for anyone out there looking for a solution to the issue I will quote that link above in case it's broken in the future.

    #if !UNITY_EDITOR && UNITY_WSA_10_0
            Debug.Log("***********************************");
            Debug.Log("File Picker start.");
            Debug.Log("***********************************");
    
            UnityEngine.WSA.Application.InvokeOnUIThread(async () =>
            {
                var filepicker = new FileOpenPicker();
                // filepicker.FileTypeFilter.Add("*");
                filepicker.FileTypeFilter.Add(".txt");
    
                var file = await filepicker.PickSingleFileAsync();
                UnityEngine.WSA.Application.InvokeOnAppThread(() => 
                {
                    Debug.Log("***********************************");
                    string name = (file != null) ? file.Name : "No data";
                    Debug.Log("Name: " + name);
                    Debug.Log("***********************************");
                    string path = (file != null) ? file.Path : "No data";
                    Debug.Log("Path: " + path);
                    Debug.Log("***********************************");
    
                    
    
                    //This section of code reads through the file (and is covered in the link)
                    // but if you want to make your own parcing function you can 
                    // ReadTextFile(path);
                    //StartCoroutine(ReadTextFileCoroutine(path));
    
                }, false);
            }, false);
    
            
            Debug.Log("***********************************");
            Debug.Log("File Picker end.");
            Debug.Log("***********************************");
    #endif
    

    EDIT:

    A little explanation as to what "InvokeOnUIThread" and "InvokeOnAppThread" mean.

    Think of the way your MRTK app runs on the hololens, you have the app running in it's own little environment with a MRTK specific unity engine handling function calls in your app. That app is then running inside the bigger app (the OS) of the hololens. So whenever you make calls to UWP specific functions, things that only the hololens will understand, you NEED to call those functions inside the InvokeOnUIThread. Now while you're running inside that function call if you need to make any function calls back to functions that are MRTK, unity, or your own creation you need to use InvokeOnAppThread. This essentially tells the application that you want to make some UWP function calls then at any point if you need to pass back any information from the UWP function calls while still inside the InvokeOnUIThread call, you need to use InvokeOnAppThread.

    From what I found out this is basically how this whole thing works and I figured this would be important to document.