简体   繁体   English

将FileSavePicker与MessageDialog的IUICommand事件一起使用

[英]Using FileSavePicker with MessageDialog's IUICommand event

Individually, all code works perfectly. 单独地,所有代码都可以完美运行。 The snippet for saving the file, the snippet for picking a directory to save it to and also the message dialog works great. 用于保存文件的代码段,用于选择目录以保存文件的代码段以及消息对话框都很有效。

But when I tie it all together, I get an access denied. 但是,当我把它们绑在一起时,我得到一个访问被拒绝。 I am not using the DocumentsLibrary capability since it is not required of me to do so in this case, however, enabling this capability after running into issues confirmed that it is not the issue. 我没有使用DocumentsLibrary功能,因为在这种情况下我不需要这样做,但是,在遇到问题后启用此功能确认它不是问题。

Scenario: User wants to create a new document after entering text in the text box. 场景:用户想要在文本框中输入文本后创建新文档。 A MessageDialog appears, asking them if they want to save changes to the existing file first - the user clicks Yes (save file). 出现MessageDialog ,询问他们是否要首先保存对现有文件的更改 - 用户单击是(保存文件)。

Now, here is where you handle the event that was raised by the MessageDialog . 现在,您可以在此处理MessageDialog引发的事件。

Inside the IUICommand command event handler, you test for which button was clicked, and act accordingly. 在IUICommand命令事件处理程序中,您可以测试单击了哪个按钮,并相应地执行操作。

I did this with a switch statement: 我用switch语句做了这个:

switch(command.Label) {
   case "Yes":
   SaveFile(); // extension method containing save file code that works on its own
   break;
   case "No":
   ClearDocument();
   break;
   default:
   break;
}

Now, each case works great except for the Yes button. 现在,除了Yes按钮之外,每个案例都很有效。 When you click yes, an e tension method is called which has code that saves to a file 单击“是”时,将调用e张力方法,该方法具有保存到文件的代码

It is when you click yes button that you get the ACCESS DENIED exception. 当您单击是按钮时,您将获得ACCESS DENIED异常。 Details of the exception didn't reveal anything. 例外的细节没有透露任何内容。

I think that it has something to do with how I am using the MesaageDialog . 我认为它与我如何使用MesaageDialog But after searching for hours I have yet to find a sample on how to save a file with the FileSavePicker when a MesaageDialog button is pressed. 但是在搜索了几个小时之后,我还没有找到关于如何在按下MesaageDialog按钮时使用FileSavePicker保存文件的示例。

Any ideas in how this should be done? 有关如何做到这一点的任何想法?

Update w/ Code 更新w / Code

When the user clicks the New document button on the AppBar, this method fires: 当用户单击AppBar上的“新建文档”按钮时,此方法将触发:

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: 和FileSavePicker的东西:

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);
    }
}

Any progress on this issue? 这个问题有什么进展吗? I currently have the same problem. 我目前有同样的问题。 I have also found that the same problem occurs if a second MessageDialog is shown in the IUICommand event. 我还发现,如果在IUICommand事件中显示第二个MessageDialog则会出现同样的问题。

My solution is to cancel the first operation (that shows the first message dialog). 我的解决方案是取消第一个操作(显示第一个消息对话框)。 Here some code I'm using (it's accessible in a global object): 这里有一些我正在使用的代码(它可以在全局对象中访问):

    private IAsyncInfo mActiveDialogOperation = null;
    private object mOperationMutex = new object();

    private void ClearActiveOperation(IAsyncInfo operation)
    {
        lock (mOperationMutex)
        {
            if (mActiveDialogOperation == operation)
                mActiveDialogOperation = null;
        }
    }

    private void SetActiveOperation(IAsyncInfo operation)
    {
        lock (mOperationMutex)
        {
            if (mActiveDialogOperation != null)
            {
                mActiveDialogOperation.Cancel();
            }

            mActiveDialogOperation = operation;
        }
    }

    public void StopActiveOperations()
    {
        SetActiveOperation(null);
    }

    public async void ShowDialog(MessageDialog dialog)
    {
        StopActiveOperations();

        try
        {
            IAsyncOperation<IUICommand> newOperation = dialog.ShowAsync();
            SetActiveOperation(newOperation);
            await newOperation;
            ClearActiveOperation(newOperation);
        }
        catch (System.Threading.Tasks.TaskCanceledException e)
        {
            System.Diagnostics.Debug.WriteLine(e.Message);
        }
    }

So every time I want to show a MessageDialog I call ShowDialog. 因此,每次我想显示MessageDialog时,我都会调用ShowDialog。 This will cancel the current dialog if any (then a TaskCanceledException occurs). 这将取消当前对话框(如果有)(然后发生TaskCanceledException)。

In the case when I will use a FileSavePicker, I call StopActiveOperations before PickSaveFileAsync is called. 在我将使用FileSavePicker的情况下,我在调用PickSaveFileAsync之前调用StopActiveOperations。

This works but I can't say I like it. 这有效,但我不能说我喜欢它。 It feels like I'm doing something wrong. 感觉我做错了什么。

OK, now I have figured it out :-). 好的,现在我已经弄明白了:-)。 The documentation says explicit that you shouldn't show new popups/file pickers in the UICommand: 文档明确表示您不应在UICommand中显示新的弹出窗口/文件选择器:

http://msdn.microsoft.com/en-US/library/windows/apps/windows.ui.popups.messagedialog.showasync http://msdn.microsoft.com/en-US/library/windows/apps/windows.ui.popups.messagedialog.showasync

This is an example of a bad way to do it: 这是一个不好的方法的例子:

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        MessageDialog dialog = new MessageDialog("Press ok to show new dialog (the application will crash).");
        dialog.Commands.Add(new UICommand("OK", new UICommandInvokedHandler(OnDialogOkTest1)));
        dialog.Commands.Add(new UICommand("Cancel"));

        await dialog.ShowAsync();
    }

    private async void OnDialogOkTest1(IUICommand command)
    {
        MessageDialog secondDialog = new MessageDialog("This is the second dialog");
        secondDialog.Commands.Add(new UICommand("OK"));

        await secondDialog.ShowAsync();
    }

This is the correct way to do it: 这是正确的方法:

    private async void Button_Click_1(object sender, RoutedEventArgs e)
    {
        MessageDialog dialog = new MessageDialog("Press ok to show new dialog");
        UICommand okCommand = new UICommand("OK");
        UICommand cancelCommand = new UICommand("Cancel");

        dialog.Commands.Add(okCommand);
        dialog.Commands.Add(cancelCommand);

        IUICommand response = await dialog.ShowAsync();

        if( response == okCommand )
        {
            MessageDialog secondDialog = new MessageDialog("This is the second dialog");
            secondDialog.Commands.Add(new UICommand("OK"));

            await secondDialog.ShowAsync();
        }
    }

Quite simple actually, I should have get this earlier... 实际上非常简单,我应该早点得到这个......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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