【问题标题】:Using FileSavePicker with MessageDialog's IUICommand event将 FileSavePicker 与 MessageDialog 的 IUICommand 事件一起使用
【发布时间】:2013-01-05 21:14:24
【问题描述】:

就个人而言,所有代码都能完美运行。 sn-p 用于保存文件,sn-p 用于选择要保存的目录以及消息对话框都很好用。

但是当我将它们捆绑在一起时,我的访问被拒绝了。我没有使用 DocumentsLibrary 功能,因为在这种情况下我不需要这样做,但是,在遇到问题后启用此功能确认它不是问题。

场景: 用户希望在文本框中输入文本后创建一个新文档。出现MessageDialog,询问他们是否要先保存对现有文件的更改 - 用户单击“是”(保存文件)。

现在,您可以在此处处理 MessageDialog 引发的事件。

在 IUICommand 命令事件处理程序中,您可以测试单击了哪个按钮,并采取相应措施。

我用 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;
}

现在,除了“是”按钮之外,每个案例都很好用。当您单击是时,将调用一个 e 张力方法,该方法具有保存到文件的代码

当您单击“是”按钮时,您会收到 ACCESS DENIED 异常。异常的细节没有透露任何信息。

我认为这与我使用MesaageDialog 的方式有关。但是在搜索了几个小时之后,我还没有找到一个示例,说明如何在按下MesaageDialog 按钮时使用FileSavePicker 保存文件。

关于如何做到这一点的任何想法?

更新代码

当用户单击 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();
    }
}

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

【问题讨论】:

  • 您需要显示 SaveFile() 方法。可能您无法访问您的文件。尝试选择其他文件或通过 try and catch 捕获此 ex。
  • @NorbertPisz:谢谢!现在我可以再次访问我的 PC,我现在将发布完整代码。
  • @NorbertPisz 已更新代码。 :)
  • @NorbertPisz - 感谢您的链接。不过,我不确定我是否关注。

标签: c# .net xaml windows-8 microsoft-metro


【解决方案1】:

在这个问题上有什么进展吗?我目前有同样的问题。我还发现如果在IUICommand 事件中显示第二个MessageDialog,也会出现同样的问题。

我的解决方案是取消第一个操作(显示第一个消息对话框)。这是我正在使用的一些代码(可以在全局对象中访问):

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

所以每次我想显示 MessageDialog 时,我都会调用 ShowDialog。如果有的话,这将取消当前对话框(然后发生 TaskCanceledException)。

如果我将使用 FileSavePicker,我会在调用 PickSaveFileAsync 之前调用 StopActiveOperations。

这行得通,但我不能说我喜欢它。感觉自己做错了什么。

【讨论】:

    【解决方案2】:

    好的,现在我想通了:-)。文档明确指出您不应在 UICommand 中显示新的弹出窗口/文件选择器:

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

    这是一个糟糕方法的例子:

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

    这是正确的做法:

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

    其实很简单,我应该早点搞定的……

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-16
      • 2016-05-27
      • 1970-01-01
      • 2011-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多