Any way to circumvent "Dialogs must be user-initiated" exception?
Asked Answered
P

3

11

My app has a 'open file' button. Before launching the OpenFileDialog, it asks whether the user wants to save the current file, and if they do, it launches a SaveFileDialog. It then launches the OpenFileDialog. Pretty standard stuff.

My problem is that silverlight then sees the OpenFileDialog.ShowDialog() method as not user-initiated, and I get a SecurityException.

Is there any known reasonable way to avoid this exception? Surely this is a pretty standard scenario?

The app is within a browser.

Any ideas welcome

EDIT:

Sorry, not allowed to release actual code :( The logic is pretty simple though: In psuedocode the 'OpenFile" button press event calls a method something like:

*Launch a new SL message asking whether to save first.

*On message window yes/no clicked: -If No, Go to Load -If Yes, Launch SaveFileDialog.ShowDialog(), go to Load

*Load: Launch An Open File Dialog

EDIT 2: Mini programme...

XML content for the main page:

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

Code:

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;
    }
}
}
Plato answered 4/11, 2011 at 10:1 Comment(9)
Can you post the code you have.Diocese
Have you tried writing extension method for ShowDialog() like ShowDialog(string question) which would first show MsgBox and then possibly call basic ShowDiaglog()?Kyat
@neurotix: I just gave it a go; same result I'm afraid :(Plato
Well the typicall route is to call SaveFileDialog's ShowDialog() first, then OpenFile(). I assume (from the pseudocode above) that you actually skip ShowDialog(). Is that right?Kyat
No, it's not skipped. I beg your pardon; I've corrected what I wrote. The SaveFileDialog is launched (i.e. 'ShowDialog()') if the user asks to save. In SL, this freezes the thread until the dialog is closed. Then, once the SaveFile dialog has closed, it moves on to the OpenFileDialog.ShowDialog() bitPlato
I think the problem is becouse you launch OpenFile() in another method. Could you try to do it right after ShowDialog() in same method?Kyat
I understand you can't show us your real code. Could you instead post a short but complete program that demonstrates the problem?Underwear
@AakashM: Code added, if it helps.Plato
@neurotix: they're in the same method.Plato
G
3

It may be a standard scenario for a desktop application but you aren't creating a desktop application. You are creating a component that runs in a secure sandbox and that comes with some fairly stringent restrictions for good reasons.

There is no slick way to handle this scenario. You could provide a close "document" feature which will popup a confirmation box warning the continuing will loses work.

In an attempt to open another "document" whilst the current is unsaved all you can do is display message instructing the user on their choices, either close the current "document" and abandon its changes or to choose to save. The user will have to manually perform these actions and then choose again to open a "document".

You might be able to improve things a bit if your app supported multiple "open" documents, at least the user wouldn't be taxed for openning a "document".

Geophagy answered 4/11, 2011 at 18:48 Comment(2)
Hey, thanks for your answer. Could I throw the same question at you that I asked Jehof, above? Why is openfiledialog treated differently to a message box? e.g. the following does not cause an exception, and still 'spams' the user: for(int i = 0; i < 1000000; i++){ MessageBox.Show("SPAM!"); }Plato
spamming user is considered less harmful as giving SL application acces to actual users HD drive by means of SaveAs or OpenFile dialogs where first can be used to write virus on disk, and second to steal sensible information from user.Siegfried
W
4

A short answer to your question is "NO", cause the second Dialog isn´t user-initiated anymore for the silverlight runtime. The same is true if you display a MessageBox before opening a Dialog.

Here´s some information from MSDN about security restrictions on Dialogs

For security purposes, if a Silverlight application is a sandboxed application, file and print dialog boxes must be user-initiated. This means you must show them from a user-initiated action, such as the click event handler for a button. If you attempt to show a dialog box from non-user initiated code, a SecurityException will occur. In addition, there is a limit on the time allowed between when the user initiates the dialog and when the dialog is shown. If the time limit between these actions is exceeded, an exception will occur. When you are using the Visual Studio debugger with a dialog box, a SecurityException will be thrown if you set a breakpoint between dialog box creation and showing the dialog box. Because of the user-initiated restrictions, this is the expected behavior. If you set a breakpoint after the call to ShowDialog, no exception will be thrown.

If you attempt to show the dialog box from KeyDown event handlers and other synchronous calls to application code, such as LayoutUpdated or SizeChanged event handlers, an exception will be thrown. However, an exception will not be thrown when the application is hosted in Internet Explorer, running in protected mode.

The Silverlight plug-in has limited support for dialog boxes when the plug-in is in full-screen mode. In most cases, displaying the dialog box in full-screen mode will cause the plug-in to revert to embedded mode. However, to avoid issues on some browsers, you should exit full-screen mode before using these classes. In Silverlight applications that run outside the browser, you can display a prompt to the user to enable dialog boxes in full-screen mode. Also, the user initiation restrictions are relaxed for trusted applications. For more information, see Trusted Applications.

The time limit, could be easily tested with following code:

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

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

When you really hit fast the "Enter"-Key when the MessageBox gets displayed, the OpenFileDialog gets displayed afterwards, raising no security exception. But if you leave the MessageBox open for a small amount of time, after closing the MessageBox a SecurityException is raised.

I think the time limit is the problem showing two Dialogs one after another, cause the time limit will exceed showing the first one.

Waxman answered 4/11, 2011 at 12:22 Comment(2)
Hey thanks for your answer. A question though: Why is openfiledialog treated differently to a message box? e.g. the following does not cause an exception, and still 'spams' the user for(int i = 0; i < 1000000; i++){ MessageBox.Show("SPAM!"); }Plato
@user495625: A MessageBox displays only text, while a OpenFileDialog/SaveFileDialog is used to access local files and resources and has therefore a higher security risk.Waxman
G
3

It may be a standard scenario for a desktop application but you aren't creating a desktop application. You are creating a component that runs in a secure sandbox and that comes with some fairly stringent restrictions for good reasons.

There is no slick way to handle this scenario. You could provide a close "document" feature which will popup a confirmation box warning the continuing will loses work.

In an attempt to open another "document" whilst the current is unsaved all you can do is display message instructing the user on their choices, either close the current "document" and abandon its changes or to choose to save. The user will have to manually perform these actions and then choose again to open a "document".

You might be able to improve things a bit if your app supported multiple "open" documents, at least the user wouldn't be taxed for openning a "document".

Geophagy answered 4/11, 2011 at 18:48 Comment(2)
Hey, thanks for your answer. Could I throw the same question at you that I asked Jehof, above? Why is openfiledialog treated differently to a message box? e.g. the following does not cause an exception, and still 'spams' the user: for(int i = 0; i < 1000000; i++){ MessageBox.Show("SPAM!"); }Plato
spamming user is considered less harmful as giving SL application acces to actual users HD drive by means of SaveAs or OpenFile dialogs where first can be used to write virus on disk, and second to steal sensible information from user.Siegfried
S
0

You should be showing SaveFileDialog in mouse Click handler immediately. In your case that would be in private void b_Click.

Putting some obstacles between mouse click and SaveFileDialog won't work.

Siegfried answered 4/11, 2011 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.