有没有绕过“对话框必须由用户启动”异常的方法?

11

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

我的问题是Silverlight随后将OpenFileDialog.ShowDialog()方法视为非用户启动,因此我会收到SecurityException。

是否有任何已知的合理方法可以避免此异常?这肯定是一个非常标准的情况吧?

该应用程序位于浏览器中。

欢迎任何想法

编辑:

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

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

*在消息窗口上单击是/否: - 如果是No,则转到Load。 - 如果是Yes,则启动SaveFileDialog.ShowDialog(),然后转到Load。

*Load: 启动打开文件对话框

编辑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;
    }
}
}

1
你可以贴出你有的代码吗? - ChrisF
不,它没有被跳过。请原谅,我已经纠正了我写的内容。如果用户要保存,SaveFileDialog会被启动(即“ShowDialog()”)。 在SL中,这会冻结线程直到对话框关闭。 然后,一旦SaveFile对话框关闭,它就会继续进行OpenFileDialog.ShowDialog()部分。 - user495625
我知道您不能展示真实的代码。您能否发布一个简短但完整的程序,以演示问题? - AakashM
@AakashM:代码已添加,如果有帮助的话。 - user495625
@neurotix:它们在同一个方法中。 - user495625
显示剩余4条评论
3个回答

4
您的问题的简短回答是“不”,因为对于Silverlight运行时来说,第二个对话框不再是用户启动的。如果在打开对话框之前显示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();
}

当你在显示消息框时快速按下“Enter”键时,随后会显示OpenFileDialog,不会引发安全异常。但是,如果你让消息框保持打开一段时间,在关闭消息框后,会引发SecurityException。
我认为时间限制是连续显示两个对话框的问题,因为时间限制将超过显示第一个对话框的时间。

嘿,感谢您的回答。不过有一个问题: 为什么OpenFileDialog与MessageBox的处理方式不同呢? 例如,以下代码不会引发异常,但仍会“垃圾邮件”用户:for(int i = 0; i < 1000000; i++){ MessageBox.Show("SPAM!"); } - user495625
@user495625:MessageBox仅显示文本,而OpenFileDialog/SaveFileDialog用于访问本地文件和资源,因此具有更高的安全风险。 - Jehof

3
这可能是一个标准的桌面应用程序场景,但你不是在创建桌面应用程序。你正在创建在安全沙箱中运行的组件,并且出于一些非常严格的原因,带有一些限制。处理这种情况没有简单的方法。您可以提供一个关闭“文档”的功能,这将弹出一个确认框,警告用户继续操作会丢失工作。如果当前未保存时尝试打开另一个“文档”,则可以显示提示消息,指示用户其选择,要么关闭当前“文档”并放弃更改,要么选择保存。用户必须手动执行这些操作,然后再次选择打开“文档”。如果您的应用程序支持多个“打开”文档,则可能可以改善一些情况,至少用户不会因打开“文档”而感到疲劳。

嘿,谢谢你的回答。我能向你提出我之前问Jehof的同样问题吗? 为什么OpenFileDialog与MessageBox处理方式不同?例如,以下代码不会引发异常,但仍会“垃圾邮件”用户: for(int i = 0; i < 1000000; i++){ MessageBox.Show("SPAM!"); } - user495625
垃圾邮件用户被认为比让SL应用程序访问实际用户的硬盘驱动器(通过SaveAs或OpenFile对话框)更少有害,其中第一个可以用于在磁盘上写入病毒,第二个可以用于从用户那里窃取敏感信息。 - Valentin Kuzub

0
你应该立即在鼠标 Click 处理程序中显示 SaveFileDialog。 在你的情况下,这将在 private void b_Click 中完成。
在鼠标点击和 SaveFileDialog 之间设置一些障碍是行不通的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接