"Dialogs must be user-initiated." with SaveFileDialog in Silverlight 3
Asked Answered
D

5

18

I am working on a Silverlight 3 app with C#. I would like to allow the user to download an image from the Silverlight app. I am using SaveFileDialog to perform the file download task. The flow goes this way:

  1. User clicks on Download button in the SL app.
  2. Web service call invoked to get the image from server
  3. OnCompleted async event handler of the web method call get invoked and receives the binary image from the server
  4. Within the OnCompleted event handler, SaveFileDialog prompted to user for saving the image to computer.
  5. Stream the image to the file on user's harddrive.

I am using the following code in a function which is called from the OnCompleted event handler to accomplish SaveFileDialog prompt and then streaming to file.

            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "JPG Files|*.jpg" + "|All Files|*.*";
            bool? dialogResult = dialog.ShowDialog();

            if (dialogResult == true)
            {
                using (Stream fs = (Stream)dialog.OpenFile())
                {
                    fs.Write(e.Result, 0, e.Result.Length);
                    fs.Close();
                }
            }

The SaveFileDialog would throw the error "Dialogs must be user-initiated." when invoking ShowDialog method in the above code. What could i be missing here? How to overcome this?

Denaedenarius answered 30/8, 2009 at 22:25 Comment(0)
C
20

What this error message means is that you can only show a SaveFileDialog in response to a user initiated event, such as a button click. In the example you describe, you are not showing SaveFileDialog in response to a click, but rather in response to a completed http request (which is not considered a user initiated event). So, what you need to do to get this to work is, in the Completed event of the http request, show some UI to the user saying "download completed, click here to save the file to your computer", and when the user clicks on this message, display the SaveFileDialog.

Crabtree answered 31/8, 2009 at 17:53 Comment(3)
I got the same error message trying to use SaveFileDialog directly from a Button_Click event handler because I was doing some validation in the method before calling new SaveFileDialog(). JumpingJezza's link below shows a good example, but it appears that the key is to have new SaveFileDialog() as the first line in your button event handler. After that, you can seemingly do whatever else you like.Landin
And "first" line really means first. I was debugging someone elses code and an out commented code block in a button click event handler caused the mentioned exception.Unstable
I think this is rather a problem of time before the savedialog open. If you put a breakpoint before dialog.ShowDialog() error happens. See dotnetslang.wordpress.com/2011/03/12/…Mainmast
R
5

How about asking first, before downloading? It seems to suggest from the error message that it is the way Silverlight wants you to prompt to ensure it knows a user requested the action, not you spaming the user with popups.

Silverlight security model aside, I'd rather not wait for a download to finish before being asked where to put it!

Recollected answered 31/8, 2009 at 0:13 Comment(0)
C
1

As Keith mentioned this is by design. This tutorial gives an excellent example using code which I used to download a file from the server in the "correct" way. (Works in Silverlight 4 too)

Clementeclementi answered 8/12, 2010 at 4:4 Comment(1)
You can also create the SaveFileDialog in the button event handler. The key is to make sure the constructor is the first line of the method.Landin
D
1

I just started on Silverlight 4 and had the same issue. It seems that if you manually create event handlers, the security exception is thrown, even if the event handler is handling a button click event with the correct parameters, but if you use the "create a new event handler" option on the button in Xaml under the click event, the new event handler, with the same code and parameters now works....this is one of the many "corky" things that I have come across since starting the transition from WPF to Silverlight.

Diphtheria answered 6/1, 2011 at 14:58 Comment(0)
P
1
Private _syncContext As SynchronizationContext
Private mBigStream As Stream

 Private Sub btnSave_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles btnSave.Click
    Try
        Dim saveDialog As New SaveFileDialog

        saveDialog.Filter = "Word |*.doc"
        saveDialog.DefaultExt = ".doc"

        If saveDialog.ShowDialog() Then
            Try
                mBigStream = saveDialog.OpenFile()

                _syncContext = SynchronizationContext.Current

                oWebService.GetReportAsync(Params, ... , _syncContext)
            Catch ex As Exception
                MessageBox.Show("File busy.")
            End Try
        End If
    Catch ex As Exception
        LogError((New System.Diagnostics.StackTrace()).GetFrame(0).GetMethod().Name.ToString, Err.Description)
    End Try
End Sub

Private Sub oWebService_GetReportCompleted(sender As Object, e As MainReference.GetReportCompletedEventArgs) Handles oWebService.GetReportCompleted
    Try
        ' e.Result is byte()

        If e.Result IsNot Nothing Then
            If e.Result.Count > 0 Then
                _syncContext.Post(Sub()
                                      Try
                                          mBigStream.Write(e.Result, 0, e.Result.Length)

                                          mBigStream.Flush()
                                          mBigStream.Close()

                                          mBigStream.Dispose()

                                          mBigStream = Nothing
                                      Catch ex As Exception
                                          LogError((New System.Diagnostics.StackTrace()).GetFrame(0).GetMethod().Name.ToString, Err.Description)
                                      End Try
                                  End Sub, Nothing)

                _syncContext = Nothing
            End If
        End If
    Catch ex As Exception
        LogError((New System.Diagnostics.StackTrace()).GetFrame(0).GetMethod().Name.ToString, Err.Description)
    End Try
End Sub
Peba answered 5/11, 2012 at 21:4 Comment(1)
Could you please explain your answer in more detail? Answers should provide direction, not just c/p code.Hexagram

© 2022 - 2024 — McMap. All rights reserved.