0

So Im now told that the FileSavePicker only creates a blank file, and that Ill have to write additional code to then actually write to the file. Ive started a Task WriteToFile after the FileSavePicker but Im unsure how to finish it. With the FileSavePicker, the user selects the folder they wish to save the file to. Where do I point to that in the WriteToFile code and how exactly do I put the file source in it? The files to be saved are all packaged with the app. Im using x.mp3 as an example here.

    public class SoundData : ViewModelBase
    {
        public string Title { get; set; }
        public string FilePath { get; set; }



        public RelayCommand<string> SaveSoundAs { get; set; }

        private async void ExecuteSaveSoundAs(string soundPath)
        {

        string path = @"appdata:/x.mp3";
        StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
        StorageFile file = await folder.GetFileAsync(path);



                {
                    FileSavePicker savePicker = new FileSavePicker();
                    savePicker.SuggestedSaveFile = file;
                    savePicker.FileTypeChoices.Add("MP3", new List<string>() { ".mp3" });
                    savePicker.ContinuationData.Add("SourceSound", soundPath);
                    savePicker.SuggestedFileName = this.Title;
                    savePicker.PickSaveFileAndContinue();

                }

        }

        public async void ContinueFileSavePicker(FileSavePickerContinuationEventArgs args)
        {
            string soundPath = (string)args.ContinuationData["SourceSound"];
            StorageFile file = args.File;
            if (file != null)
            {
                // Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
                CachedFileManager.DeferUpdates(file);
                // write to file



                await FileIO.WriteTextAsync(file, file.Name);
                // Let Windows know that we're finished changing the file so the other app can update the remote version of the file.
                // Completing updates may require Windows to ask for user input.
                FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
                if (status == FileUpdateStatus.Complete) ;

            }
        }



        public SoundData()
        {
            SaveSoundAs = new RelayCommand<string>(ExecuteSaveSoundAs);
        }







    }
}
user3568429
  • 151
  • 8

1 Answers1

1

For Windows Phone you should follow this How to documentation. The workflow has changed quite a bit from Silverlight apps. Your app no longer resumes like it used to with the old Tasks.

You don't need to follow all of the steps in the doc, but an important piece is to over the OnActivated method within App.xaml.cs. Within there you will call your ContinueFileSavePicker method.

Here is a sample that you can download as well that should help.

Update

If you want to save a file that you will be shipping with your app, try the following code to initialize the picker

// Get the local file that is shipped with the app
// file but be "content" and not "resource"
string path = @"Assets\Audio\Sound.mp3";
StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFile file = await folder.GetFileAsync(path);

// Show the picker
FileSavePicker savePicker = new FileSavePicker();
// Set the file that will be saved
savePicker.SuggestedSaveFile = file;
savePicker.SuggestedFileName = "Sound";
savePicker.FileTypeChoices.Add("MP3", new List<string>() { ".mp3" });
savePicker.PickSaveFileAndContinue();

You also need to make sure that you listen to the ContractActivated event of the PhoneApplicationService. This event is fired (in 8.1 Silverlight apps) when the app returns from the picker. This is where you want to call your ContinueFileSavePicker method. If you wanted, you could always just put the logic in there.

Subscribe to the event in xaml:

<Application.ApplicationLifetimeObjects>
    <!--Required object that handles lifetime events for the application-->
    <shell:PhoneApplicationService
        ContractActivated="Application_ContractActivated"
        Launching="Application_Launching" Closing="Application_Closing"
        Activated="Application_Activated" Deactivated="Application_Deactivated"/>
</Application.ApplicationLifetimeObjects>

And in the App.xaml.cs:

private async void Application_ContractActivated(object sender, Windows.ApplicationModel.Activation.IActivatedEventArgs e)
{
    var args = e as FileSavePickerContinuationEventArgs ;
    if (args != null)
    {
        StorageFile file = args.File; 
        if (file != null) 
        { 
            // Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync. 
            CachedFileManager.DeferUpdates(file); 
            // write to file 
            await FileIO.WriteTextAsync(file, file.Name); 
            // Let Windows know that we're finished changing the file so the other app can update the remote version of the file. 
            // Completing updates may require Windows to ask for user input. 
            FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file); 
        }
    }
}
Shawn Kendrot
  • 12,425
  • 1
  • 25
  • 41
  • Thanks. I did take a look at it and the only problem I have with the sample is there is no actual file in it to save. Since Im very new to a lot of this, real world examples help the best. I can kind of see how it works but since they have no sample file to save in it, I cant see how to correctly do the source. – user3568429 Jun 04 '14 at 23:04
  • The sample does include code that uses the SaveFilePicker. check it out: http://code.msdn.microsoft.com/windowsapps/File-picker-sample-9f294cba/sourcecode?fileId=43705&pathId=1155535444 – Shawn Kendrot Jun 05 '14 at 15:12
  • True. But it doesnt seem to actually contain a file to be saved. Kinda of just goes through the motions. I went off Scenario 4 for WP and wish they included an actual file within the Project so I could see how put that in the code to be written. If I have an mp3 file at "appdata:/x.mp3", for example, I cant figure out where that goes in the code based off the sample. – user3568429 Jun 05 '14 at 15:38
  • So, you are trying to get a file that is packaged with the app? – Shawn Kendrot Jun 05 '14 at 17:07
  • Yes. To sum it up. My app has buttons, press once and they play a sound. Press and hold brings up a Context Menu with the Save To option. Right now, it saves a file but its blank. The sound files are packaged with the app. Ive never done any write code before so Im unsure how to incorporate that into the code above. – user3568429 Jun 05 '14 at 17:10
  • Great, thanks! Getting a few errors though: The 'await' operator can only be used when contained within a method or lambda expression marked with the 'async' modifier And two errors like this one for 'folder' the other for 'path': A field initializer cannot reference the non-static field, method, or property 'Tonality.ViewModels.SoundData.folder' – user3568429 Jun 09 '14 at 18:25
  • If you want to await something, it must be in an async method. I do not believe you need to wrap the picker with a Dispatcher.BeginInvoke call, so just add the async keyword to the ExecuteSaveSoundAs method. – Shawn Kendrot Jun 09 '14 at 18:35
  • Gotcha. Still gives the other two errors for the same line: A field initializer cannot reference the non-static field, method, or property 'Tonality.ViewModels.SoundData.folder' and A field initializer cannot reference the non-static field, method, or property 'Tonality.ViewModels.SoundData.path' – user3568429 Jun 09 '14 at 18:50
  • Ok. Fixed. Getting closer I think. Actually throwing an error now what I press Save To: A first chance exception of type 'System.ArgumentException' occurred in mscorlib.ni.dll An exception of type 'System.ArgumentException' occurred in mscorlib.ni.dll but was not handled in user code Additional information: Value does not fall within the expected range. – user3568429 Jun 09 '14 at 19:18
  • The above error highlights StorageFile file = await folder.GetFileAsync(path); – user3568429 Jun 09 '14 at 19:18
  • Does the file exist? Notice that I have the path = "Assets\Audio\Sound.mp3". That means that in the Application Project (WP app) I have an "Assets" folder. In that folder I have an "Audio" folder, and in that folder is a file "Sound.mp3". This file has the build action (right click file, select properties) sent to "Content". And Copy To Output Directory set to "Copy Always" – Shawn Kendrot Jun 09 '14 at 19:30
  • I sent you an email through your website. – user3568429 Jun 09 '14 at 19:58
  • Worked for me. Didn't need to add the ContractActivated attribute or event as it was there already. Thanks. [Why has no-one up voted you :-( ] – Nick Wright Jan 07 '15 at 17:14