2009-08-30 28 views
18

Estoy trabajando en una aplicación Silverlight 3 con C#. Me gustaría permitir que el usuario descargue una imagen de la aplicación Silverlight. Estoy usando SaveFileDialog para realizar la tarea de descarga de archivos. El flujo va de esta manera:"Los cuadros de diálogo deben ser iniciados por el usuario". con SaveFileDialog en Silverlight 3

  1. El usuario hace clic en el botón Descargar en la aplicación SL.
  2. llamada de servicio Web invoca para obtener la imagen del servidor
  3. OnCompleted controlador de eventos asincrónicos de la llamada al método web Cómo invocado y recibe la imagen binaria del servidor
  4. Dentro del controlador de eventos OnCompleted, SaveFileDialog impulsó a los usuarios para ahorrar la imagen a la computadora.
  5. Transmita la imagen al archivo en el disco duro del usuario.

Estoy utilizando el siguiente código en una función que se llama desde el controlador de eventos OnCompleted para llevar a cabo el aviso SaveFileDialog y luego la transmisión al archivo.

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

El SaveFileDialog tiraría el error "Diálogos deben ser iniciados por el usuario." al invocar el método ShowDialog en el código anterior. ¿Qué podría estar perdiendo aquí? ¿Cómo superar esto?

Respuesta

19

Lo que este mensaje de error significa es que solo puede mostrar un SaveFileDialog en respuesta a un evento iniciado por el usuario, como un clic de botón. En el ejemplo que describe, no muestra SaveFileDialog en respuesta a un clic, sino más bien en respuesta a una solicitud http completa (que no se considera un evento iniciado por el usuario). Entonces, lo que debe hacer para que esto funcione es que, en el evento Completado de la solicitud http, muestre al usuario una IU que diga "descarga completada, haga clic aquí para guardar el archivo en su computadora", y cuando el usuario haga clic en este mensaje, muestre SaveFileDialog.

+8

Recibí el mismo mensaje de error tratando de usar SaveFileDialog directamente desde un controlador de eventos Button_Click porque estaba haciendo alguna validación en el método antes de llamar a un nuevo SaveFileDialog(). El enlace de JumpingJezza a continuación muestra un buen ejemplo, pero parece que la clave es tener un nuevo SaveFileDialog() como la * primera * línea en el controlador de eventos de tu botón. Después de eso, aparentemente puedes hacer lo que quieras. – Jedidja

+0

Y la "primera" línea realmente significa _primero_.Estaba depurando el código de alguien más y un bloque de código comentado en un controlador de evento de clic de botón provocó la excepción mencionada. – faester

+2

Creo que esto es más bien un problema de tiempo antes de que se abra el archivo de registro de guardado. Si coloca un punto de interrupción antes del cuadro de diálogo, se produce el error ShowDialog(). Consulte http://dotnetslang.wordpress.com/2011/03/12/using-the-savefiledialog-dialogs-must-be-user-initiated-exception/ – maxence51

5

¿Qué le parece primero, antes de descargar? Parece sugerir, a partir del mensaje de error, que Silverlight desea que se lo solicite para asegurarse de que sabe que un usuario solicitó la acción, no de que el usuario se convierta en pop-ups.

Dejando a un lado el modelo de seguridad de Silverlight, prefiero no esperar a que finalice una descarga antes de que me pregunten dónde ponerlo.

1

Como Keith mencionó esto es por diseño. El tutorial This brinda un excelente ejemplo utilizando código que utilicé para descargar un archivo del servidor de la manera "correcta". (Funciona en Silverlight 4 también)

+1

También puede crear SaveFileDialog en el controlador de eventos del botón. La clave es asegurarse de que el constructor sea la primera línea del método. – Jedidja

1

Acabo de comenzar con Silverlight 4 y tuve el mismo problema. Parece que si crea manualmente manejadores de eventos, se lanza la excepción de seguridad, incluso si el manejador de eventos maneja un evento de clic de botón con los parámetros correctos, pero si usa la opción "crear un nuevo manejador de eventos" en el botón en Xaml bajo el evento click, el nuevo controlador de eventos, con el mismo código y parámetros ahora funciona ... esta es una de las muchas cosas "tontas" que he encontrado desde que comencé la transición de WPF a Silverlight.

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 
+2

¿Podría explicar su respuesta con más detalle? Las respuestas deben proporcionar la dirección, no solo el código c/p. – CodeMouse92

Cuestiones relacionadas