简体   繁体   中英

How to call FileSavePicker when user clicks button on MessageDialog?

I have a Windows 8 Metro style app and I have run into what should be a simple thing to accomplish, but am finding it extremely difficult to come up with a solution. As it's been a week now and I still haven't found a solution, I am offering a bounty of 300 rep for a working solution.

Scenario:

When I edit a textbox, and click Create New Document, a MessageDialog appears asking if I want to save changes to the existing file before creating a new one. If I click "Yes, save changes" - then the FileSavePicker opens, allowing me to save the file.

The Problem: When I click "Yes, save changes", I get an ACCESSDENIED exception. I have set breakpoints but exception details have not revealed any other information.

Notes: I do not have DocumentsLibrary declaration enabled because in this case that is not a requirement, and when this did not work, I then tried enabling it anyway - and I still got the error.

Also, all pieces of code work perfectly on their own (separate from each other), but when you tie it all together, it falls apart when the FileSavePicker tried to open.

I believe this may be a Threading issue. But I'm not sure.

MessageDialog on MSDN.

The code I have is below:

async private void New_Click(object sender, RoutedEventArgs e)
{
    if (NoteHasChanged)
    {
        // Prompt to save changed before closing the file and creating a new one.
        if (!HasEverBeenSaved)
        {

        MessageDialog dialog = new MessageDialog("Do you want to save this file before creating a new one?",
            "Confirmation");
        dialog.Commands.Add(new UICommand("Yes", new UICommandInvokedHandler(this.CommandInvokedHandler)));
        dialog.Commands.Add(new UICommand("No", new UICommandInvokedHandler(this.CommandInvokedHandler)));
        dialog.Commands.Add(new UICommand("Cancel", new UICommandInvokedHandler(this.CommandInvokedHandler)));

        dialog.DefaultCommandIndex = 0;
        dialog.CancelCommandIndex = 2;

        // Show it.
        await dialog.ShowAsync();
    }
    else { }
}
else
{
    // Discard changes and create a new file.
    RESET();
}

}

And the FileSavePicker stuff:

private void CommandInvokedHandler(IUICommand command)
{
    // Display message showing the label of the command that was invoked
    switch (command.Label)
    {
        case "Yes":

            MainPage rootPage = this;
            if (rootPage.EnsureUnsnapped())
            {
                // Yes was chosen. Save the file.
                SaveNewFileAs();
            }
            break;
        case "No":
            RESET(); // Done.
            break;
        default:
            // Not sure what to do, here.
            break;
    }
}

async public void SaveNewFileAs()
{
    try
    {
        FileSavePicker saver = new FileSavePicker();
        saver.SuggestedStartLocation = PickerLocationId.Desktop;
        saver.CommitButtonText = "Save";
        saver.DefaultFileExtension = ".txt";
        saver.FileTypeChoices.Add("Plain Text", new List<String>() { ".txt" });

        saver.SuggestedFileName = noteTitle.Text;

        StorageFile file = await saver.PickSaveFileAsync();
        thisFile = file;

        if (file != null)
        {
            CachedFileManager.DeferUpdates(thisFile);

            await FileIO.WriteTextAsync(thisFile, theNote.Text);

            FileUpdateStatus fus = await CachedFileManager.CompleteUpdatesAsync(thisFile);
            //if (fus == FileUpdateStatus.Complete)
            //    value = true;
            //else
            //    value = false;

        }
        else
        {
            // Operation cancelled.
        }

    }
    catch (Exception exception)
    {
        Debug.WriteLine(exception.InnerException);
    }
}

How can I get this to work?

The problem seems to be that you're opening a FileSavePicker before the MessageDialog is closed (and before the await dialog.ShowAsync() call is terminated). I am not sure of why this behavior happens, but a workaround can be easily done. I'll only make an example, it will be up to you to adapt it to your needs and model.

First, declare an Enum .

enum SaveChoice
{
    Undefined,
    Save,
    DoNotSave
}

Then, create a field/property in your class. Again, this is not the most wise design choice but it works as an example.

SaveChoice _currentChoice;

Then, modify your CommandInvokeHandler method:

void CommandInvokedHandler(IUICommand command)
{
    // Display message showing the label of the command that was invoked
    switch (command.Label)
    {
        case "Yes":
            var rootPage = this;
            if (rootPage.EnsureSnapped())
                _currentChoice = SaveChoice.Save;
            break;
        case "No":
            _currentChoice = SaveChoice.DoNotSave;
            break;
        default:
            _currentChoice = SaveChoice.Undefined;
            // Not sure what to do, here.
            break;
    }
}

Finally, edit your New_Click method:

//Continues from dialog.CancelCommandIndex = 2;
// Show it.
await dialog.ShowAsync();
if (_currentChoice == SaveChoice.Save) SaveNewFileAs();

You can introduce a tiny delay before calling the file picker to ensure the message dialog has ended.

await Task.Delay(10);
StorageFile file = await saver.PickSaveFileAsync();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM