【问题标题】:Any way to circumvent "Dialogs must be user-initiated" exception?有什么方法可以规避“对话框必须由用户启动”异常?
【发布时间】:2011-12-21 21:26:51
【问题描述】:

我的应用有一个“打开文件”按钮。在启动 OpenFileDialog 之前,它会询问用户是否要保存当前文件,如果是,它会启动 SaveFileDialog。然后它启动 OpenFileDialog。很标准的东西。

我的问题是,silverlight 将 OpenFileDialog.ShowDialog() 方法视为不是用户启动的,因此我得到了 SecurityException。

是否有任何已知的合理方法可以避免此异常?当然这是一个非常标准的场景?

应用在浏览器中。

欢迎任何想法

编辑:

抱歉,不允许发布实际代码 :( 不过逻辑非常简单:在伪代码中,“OpenFile”按钮按下事件调用类似以下的方法:

*启动一条新的 SL 消息,询问是否先保存。

*在消息窗口上单击是/否: - 如果没有,请转到加载 - 如果是,启动 SaveFileDialog.ShowDialog(),去加载

*加载: 启动打开文件对话框

编辑 2: 小程序...

主页的 XML 内容:

<Grid x:Name="LayoutRoot" Background="White">
    <Button Content="Open" Click="Button_Click"/>
</Grid>

代码:

using System.Windows;
using System.Windows.Controls;

namespace SilverlightApplication15
{
public partial class MainPage : UserControl
{
    AskWindow aw = new AskWindow();

    public MainPage()
    {
        InitializeComponent();
        aw.Closed += new System.EventHandler(aw_Closed);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        aw.Show();
    }

    private void aw_Closed(object sender, System.EventArgs e)
    {
        if (aw.DialogResult == true)
        {
            SaveFileDialog svd = new SaveFileDialog();
            svd.ShowDialog();
        }


        OpenFileDialog ofd = new OpenFileDialog();
        ofd.ShowDialog();//Causes security exception
    }
}

public class AskWindow : ChildWindow
{
    public AskWindow()
    {
        Button b = new System.Windows.Controls.Button();
        b.Click += new System.Windows.RoutedEventHandler(b_Click);
        b.Content = "Yes, save it";
        this.Content = b;
    }

    private void b_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        this.DialogResult = true;
    }
}
}

【问题讨论】:

  • 你能把你的代码贴出来吗。
  • 您是否尝试过为 ShowDialog() 编写扩展方法,例如 ShowDialog(string question),它首先显示 MsgBox,然后可能调用基本的 ShowDiaglog()?
  • @neurotix:我试了一下;恐怕同样的结果:(
  • 嗯,典型的方法是先调用 SaveFileDialog 的 ShowDialog(),然后是 OpenFile()。我假设(根据上面的伪代码)您实际上跳过了 ShowDialog()。对吗?
  • 不,它没有被跳过。请再说一遍;我已经更正了我写的内容。如果用户要求保存,则会启动 SaveFileDialog(即“ShowDialog()”)。在 SL 中,这会冻结线程,直到对话框关闭。然后,一旦 SaveFile 对话框关闭,它就会移动到 OpenFileDialog.ShowDialog() 位

标签: c# silverlight openfiledialog savefiledialog


【解决方案1】:

您的问题的简短回答是“否”,因为 Silverlight 运行时的第二个对话框不再由用户启动。如果在打开 Dialog 之前显示 MessageBox,也是如此。

这里有一些来自MSDN 的关于对话框安全限制的信息

出于安全考虑,如果 Silverlight 应用程序是沙盒应用程序,则文件和打印对话框必须由用户启动。这意味着您必须从用户启动的操作(例如按钮的单击事件处理程序)中显示它们。如果您尝试从非用户启动的代码中显示对话框,则会发生 SecurityException。此外,在用户启动对话和显示对话之间允许的时间有限制。如果超出这些操作之间的时间限制,则会发生异常。将 Visual Studio 调试器与对话框一起使用时,如果在对话框创建和显示对话框之间设置断点,则会引发 SecurityException。由于用户启动的限制,这是预期的行为。如果在调用 ShowDialog 之后设置断点,则不会抛出异常。

如果您尝试从 KeyDown 事件处理程序和对应用程序代码的其他同步调用(例如 LayoutUpdated 或 SizeChanged 事件处理程序)显示对话框,则会引发异常。但是,当应用程序托管在 Internet Explorer 中并在保护模式下运行时,不会引发异常。

当插件处于全屏模式时,Silverlight 插件对对话框的支持有限。在大多数情况下,以全屏模式显示对话框会导致插件恢复为嵌入模式。但是,为避免某些浏览器出现问题,您应该在使用这些类之前退出全屏模式。在浏览器外运行的 Silverlight 应用程序中,您可以向用户显示提示以在全屏模式下启用对话框。此外,对于受信任的应用程序,放宽了用户启动限制。有关详细信息,请参阅受信任的应用程序。

时间限制,可以用以下代码轻松测试:

private void OpenDialog(object sender, RoutedEventArgs e) {
  MessageBox.Show("test");

  OpenFileDialog fileDialog = new OpenFileDialog();
  var result = fileDialog.ShowDialog();
}

当您在显示 MessageBox 时真正快速按下“Enter”键时,随后会显示 OpenFileDialog,不会引发安全异常。但是如果你让 MessageBox 保持打开一小段时间,在关闭 MessageBox 之后就会引发 SecurityException。

我认为时间限制是一个接一个显示两个对话框的问题,导致时间限制会超过显示第一个。

【讨论】:

  • 您好,感谢您的回答。但是有一个问题:为什么 openfiledialog 对待消息框的方式不同?例如以下不会导致异常,并且仍然向用户发送“垃圾邮件” for(int i = 0; i
  • @user495625:MessageBox 只显示文本,而 OpenFileDialog/SaveFileDialog 用于访问本地文件和资源,因此具有更高的安全风险。
【解决方案2】:

这可能是桌面应用程序的标准方案,但您不是在创建桌面应用程序。您正在创建一个在安全沙箱中运行的组件,并且有一些相当严格的限制是有充分理由的。

没有巧妙的方法来处理这种情况。您可以提供关闭“文档”功能,该功能将弹出一个确认框,警告继续将丢失工作。

在当前未保存的情况下尝试打开另一个“文档”,您所能做的就是显示消息,指示用户选择,关闭当前“文档”并放弃其更改或选择保存。用户必须手动执行这些操作,然后再次选择打开“文档”。

如果您的应用支持多个“打开”文档,您也许可以稍微改进一下,至少用户不会因为打开一个“文档”而被征税。

【讨论】:

  • 您好,谢谢您的回答。我可以向你提出我在上面问过 Jehof 的同样问题吗?为什么 openfiledialog 对待消息框的方式不同?例如以下不会导致异常,并且仍然向用户发送“垃圾邮件”: for(int i = 0; i
  • 垃圾邮件用户被认为危害较小,因为通过 SaveAs 或 OpenFile 对话框将 SL 应用程序访问权授予实际用户 HD 驱动器,其中首先可用于在磁盘上写入病毒,其次用于窃取用户的敏感信息.
【解决方案3】:

您应该立即在鼠标 Click 处理程序中显示 SaveFileDialog。 你的情况是private void b_Click

在鼠标点击和SaveFileDialog之间设置一些障碍是行不通的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多