2009-08-30 10 views
18

Pracuję nad aplikacją Silverlight 3 z C#. Chciałbym umożliwić użytkownikowi pobranie obrazu z aplikacji Silverlight. Używam SaveFileDialog do wykonania zadania pobierania pliku. Przepływ jest następujący:"Dialogi muszą być inicjowane przez użytkownika." z SaveFileDialog w Silverlight 3

  1. Użytkownik klika przycisk Pobierz w aplikacji SL.
  2. wywołanie usługi sieci Web wywoływana uzyskać obraz z serwera
  3. OnCompleted obsługi zdarzeń asynchronicznych wstęgi wywołanie metody get wywoływana i odbiera obraz binarny z serwera
  4. W ramach obsługi zdarzeń OnCompleted, SaveFileDialog monit do użytkownika do zapisywania obraz do komputera.
  5. Przesyłanie obrazu do pliku na dysku twardym użytkownika.

Korzystam z następującego kodu w funkcji, która jest wywoływana z funkcji obsługi zdarzeń OnCompleted, aby wykonać monit SaveFileDialog, a następnie przesyłać strumieniowo do pliku.

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

Plik SaveFileDialog spowodowałby błąd "Dialogi muszą być inicjowane przez użytkownika". podczas wywoływania metody ShowDialog w powyższym kodzie. Czego tu nie mogę przegapić? Jak przezwyciężyć to?

Odpowiedz

19

Co oznacza ten komunikat o błędzie, to że można wyświetlić tylko SaveFileDialog w odpowiedzi na zdarzenie inicjowane przez użytkownika, takie jak kliknięcie przycisku. W opisywanym przykładzie nie wyświetlasz SaveFileDialog w odpowiedzi na kliknięcie, ale raczej w odpowiedzi na zakończone żądanie http (które nie jest uważane za zdarzenie inicjowane przez użytkownika). Tak więc to, co musisz zrobić, aby to zadziałało, w zdarzeniu Completed z żądaniem http pokazuje użytkownikowi pewien interfejs użytkownika, mówiąc "pobieranie zakończone, kliknij tutaj, aby zapisać plik na komputerze", a kiedy użytkownik kliknie w tej wiadomości wyświetl SaveFileDialog.

+8

Mam ten sam komunikat o błędzie próbuje użyć SaveFileDialog bezpośrednio z obsługi zdarzeń Button_Click bo robiłem trochę walidacji w metodzie przed wywołaniem nowego SaveFileDialog(). Poniższy link JumpingJezza pokazuje dobry przykład, ale wydaje się, że kluczem jest posiadanie nowego SaveFileDialog() jako * pierwszego * wiersza w procedurze obsługi zdarzeń przycisku. Potem możesz pozornie robić cokolwiek innego. – Jedidja

+0

I "pierwsza" linia naprawdę oznacza _pierwszy_.Byłem debugowania ktoś kod elses i out skomentował blok kodu w obsługi zdarzeń kliknij przycisk spowodował wspomnianego wyjątku. – faester

+2

Myślę, że to raczej problem czasu, zanim otwarty zapis jest otwarty. Jeśli umieścisz punkt przerwania przed dialogiem. Błąd programu SHowDialog(). Zobacz http://dotnetslang.wordpress.com/2011/03/12/using-the-savefiledialog-dialogs-must-be-user-initiated-exception/ – maxence51

5

Co powiesz na pierwsze pytanie przed pobraniem? Wygląda na to, że z komunikatu o błędzie wynika, że ​​jest to sposób, w jaki Silverlight chce, abyś podpowiadał, że wie, że użytkownik zażądał akcji, a nie spamerujesz użytkownika za pomocą wyskakujących okienek.

Poza tym model zabezpieczeń Silverlight, wolałbym nie czekać na zakończenie pobierania, zanim zostanie zapytany, gdzie go umieścić!

1

Jak wspomniał Keith, jest to zgodne z projektem. This samouczek stanowi doskonały przykład użycia kodu, który użyłem do pobrania pliku z serwera w "prawidłowy" sposób. (Działa także w Silverlight 4)

+1

Możesz również utworzyć SaveFileDialog w module obsługi zdarzeń przycisku. Kluczem jest upewnienie się, że konstruktor jest pierwszą linią metody. – Jedidja

1

Właśnie zacząłem na Silverlight 4 i miałem ten sam problem. Wygląda na to, że jeśli ręcznie utworzysz procedury obsługi zdarzeń, zgłoszony zostanie wyjątek bezpieczeństwa, nawet jeśli procedura obsługi zdarzenia obsługuje zdarzenie kliknięcia przycisku z poprawnymi parametrami, ale jeśli użyjesz opcji "utwórz nowy moduł obsługi zdarzeń" na przycisku w Xaml pod zdarzeniem click nowa obsługa zdarzeń, z tym samym kodem i parametrami teraz działa .... jest to jedna z wielu "korkowatych" rzeczy, z którymi się zetknąłem od czasu przejścia z WPF do 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

Czy możesz wyjaśnić swoją odpowiedź bardziej szczegółowo? Odpowiedzi powinny wskazywać kierunek, a nie tylko kod c/p. – CodeMouse92

Powiązane problemy