locked
FileOpenPicker: How to provide files which are not stored locally

    Question

  • Hi,

    I have the following use case: In my app I want to provide file access via the FileOpenPicker contract. In general, when the app is launched via the contract, you can easily add a local file to the FileOpenPicker via the following function:

    args.detail.fileOpenPickerUI.add("fileId", myFile)

    ... and here comes the challenge. In my app, the files are stored on a web server and not locally. Thus, once a user chooses a file via FileOpenPicker, only then the file should be downloaded (like SkyDrive does it).

    Any idea how this can be achieved?

    Thanks,

    Jepeal

    Tuesday, July 3, 2012 3:33 PM

Answers

All replies

  • Hi,

    Base on my experience, FileOpenPicker is not stood by the feature you mentioned. If you want to let the user choose a file from a web server, please provide your own UI. The Live SDK contains a sample that demonstrates how to build a simple SkyDrive browser. You can get it from https://github.com/liveservices/LiveSDK.

    Best Regards,

    Ming Xu.


    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework

    Wednesday, July 4, 2012 1:56 PM
    Moderator
  • Hi Ming,

    thanks for your answer. In my app, I provide my own UI, but in addition I want to provide file access for other apps via FileOpenPicker. Do you mean that there is no way to download files on-the-fly when picked via FileOpenPicker?

    But how can SkyDrive handle this scenario (when a file is picked from SkyDrive via FileOpenPicker - and the file is not cached locally - the file will be downloaded on-the-fly, and once downloaded, displayed in the calling app)???

    Any ideas?

    Thanks

    Wednesday, July 4, 2012 7:49 PM
  • Hi,

    I did another test, and found actually FileOpenPicker can open files from network. Sorry for the confusion. However, you won’t be able to configure FileOpenPicker to open a network location by default. The user needs to click “Files”=>”Network”, and then type the network location.

    As for the built-in SkyDrive app, it uses a custom UI instead of a FileOpenPicker.

    Best Regards,

    Ming Xu.


    Please mark the replies as answers if they help or unmark if not.
    If you have any feedback about my replies, please contact msdnmg@microsoft.com.
    Microsoft One Code Framework


    Thursday, July 5, 2012 9:33 AM
    Moderator
  • Hi,

    not sure if we are talking about the same problem. My app should act as the provider, thus any other app which take use of the FileOpenPicker (the calling app) should be able to access files provided by my app.

    Here is a code snippet which should help to clarify the problem:

    var openPickerUI;
    var cachedFileUpdaterUI;
    
    WinJS.Application.onactivated = function (args) {
                    // app has been launched manually
    		if (args.detail.kind === activation.ActivationKind.launch) {
    		
    		}
       
                    // app has been activated via FileOpenPicker
    		else if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.fileOpenPicker) {
                           openPickerUI = args.detail.fileOpenPickerUI;
                    }
    		
    		// app has been activated via CachedFileUpdater
    		else if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.cachedFileUpdater) {
    			cachedFileUpdaterUI = args.detail.cachedFileUpdaterUI;
                            cachedFileUpdaterUI.addEventListener("fileupdaterequested", onUpdateRequested);
    		}
    		
            WinJS.UI.processAll().done(function () {
                var imageListView = document.getElementById("imageListView");
                imageListView.addEventListener("iteminvoked", onImageClicked);
            });
    };
    	
    function onImageClicked(eventObject) {
             // check if app has been started via fileOpenPicker
            if (openPickerUI) {
                Windows.Storage.ApplicationData.current.localFolder.createFileAsync("testFile.jpg").then(function (newFile) {
                    if (newFile) {
                        Windows.Storage.Provider.CachedFileUpdater.setUpdateInformation(newFile, "test", Windows.Storage.Provider.ReadActivationMode.beforeAccess, Windows.Storage.Provider.WriteActivationMode.afterWrite, Windows.Storage.Provider.CachedFileOptions.requireUpdateOnAccess);
                        openPickerUI.addFile("testId", newFile);
                    }
                });
            }
    }
    	
    function onUpdateRequested(eventObject) {
            var request = eventObject.request;
            var deferral = request.getDeferral();
    
            downloadRemoteFile(reqest.file).then(function () {
                deferral.Complete();
            });
    }

    When I did some tests with a calling app, my app was activated via FileOpenPicker and the empty file was added to the openPickerUI. I actually assumed that before the file is accessed by the calling app (when clicking on the 'Open' button in the FilePicker UI), my app is activated again via CachedFileUpdater to fill the empty file with content from cloud.
    The problem is that my app is never be called via CachedFileUpdater, can't understand why? (in the app manifest I added declarations for both the 'Cached File Updater' and the 'FileOpenPicker')

    I also did some investigation on the SkyDrive app which is handling this scenario properly. According to network monitor, when a file is picked via FileOpenPicker from Skydrive (click 'Open' button in FilePicker UI), the file is downloaded from cloud.
    I have no idea how SkyDrive is doing that?

    Thanks,
    Jepeal

    Thursday, July 5, 2012 2:29 PM
  • Hi Jepeal,

    We offer the ability for your app to provide files, but you are responsible for constructing the UI: http://msdn.microsoft.com/en-us/library/windows/apps/hh465192.aspx

    -Jeff


    Jeff Sanders (MSFT)

    Thursday, July 5, 2012 5:09 PM
    Moderator
  • Hi Jeff,

    I already understand the concept of the FileOpenPicker and also have constructed my own UI to provide files. The problem is, that when a user picks a file (which is not stored locally), I need to download the file from cloud. Actually my idea was to use CachedFileUpdater so that my app is called - before the calling app opens the file - to fill the empty file with content. But my app is never called via CachedFileUpdater.

    Here are the steps what I want to do (please see previous post for source code):

    1. User calls my app via FileOpenPicker contract
    2. A empty file is added to openPickerUI (openPickerUI.addFile("testId", newFile))
    3. Once the file is added, user has the possibility to open the file in the calling app (by clicking the 'Open' button)
    4. Now I need a way to download the data from cloud and fill the empty file with content
    5. When downloaded, file (e.g. Image) will be displayed in calling app

    All steps are pretty straight forward, except step 4, I don't know how I can implement that.

    Any ideas?

    Thanks

    Friday, July 6, 2012 2:57 PM
  • Jepeal,

    How about, when the user chooses open, download the file from your webservice to your local storage and provide that file to the picker.

    -Jeff


    Jeff Sanders (MSFT)

    Friday, July 6, 2012 6:31 PM
    Moderator
  • Hi Jeff,

    yes, that's what I want to do. So my idea was to set a closing event listener for the openPickerUI, which is fired right after the user clicked the 'Choose' button. In the event listener function (onPickerUIClosing) I then want to download the actual file. Problem here is, that it seems download takes to long and after some time my app is being closed by the system (somewhere in the middle of the download), even when I defer it.

          else if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.fileOpenPicker) {
                openPickerUI = args.detail.fileOpenPickerUI;
                openPickerUI.addEventListener("closing", onPickerUIClosing);
         }                
    }
    
        // function is called right after user chose file and just before FilePicker is closed
         function onPickerUIClosing(eventArgs) {
            if (eventArgs.isCanceled == false) {
                deferral = eventArgs.closingOperation.getDeferral();

                downloadRemoteFile(file).then(function () {
                    deferral.Complete();
                });
            }
        }

    Any idea on this?

    Thanks,

    Thomas




    Saturday, July 7, 2012 12:44 PM
  • Hi Thomas,

    Doing this in the closing event listener will not work.  You have 5 seconds to complete any task in that event before the OS can take down your application. 

    I can't remember how the file picker extension example works, so I will try and take some time later today to look at that again.

    -Jeff


    Jeff Sanders (MSFT)

    Monday, July 9, 2012 12:01 PM
    Moderator
  • Thanks a lot Jeff,

    looking forward to your response.

    Jepeal

    Monday, July 9, 2012 1:53 PM
  • Take a look at this sample: http://code.msdn.microsoft.com/windowsapps/File-picker-app-extension-0cb95155

    You will want to mirror what scenario 2 does for picking a file from a URI.  Basically when your user picks your file, you want to add the file asyncronously to the basket using fileOpenPickerUI.addFile.

    You have to first stream the file using Windows.Storage.StorageFile.createStreamedFileFromUriAsync to create a URI that can be handed back to the callng app.

    -Jeff


    Jeff Sanders (MSFT)

    Monday, July 9, 2012 3:22 PM
    Moderator
  • very good point Jeff. This was the function I was looking for.

    Thanks a lot.

    Jepeal

    Thursday, July 12, 2012 10:52 AM