2009-08-05 6 views
1

У меня есть приложение для форм Windows, с кнопкой - на обработчике событий кнопки, мне нужно загрузить файл с помощью SaveFileDialog. Но мне нужно сделать это асинхронно в отдельном потоке.Как использовать SaveFileDialog асинхронно?

До сих пор я придумал этот код, но я не знаю, если мой подход является ошибочным или OK:

 private void btnDownload_Click(object sender, EventArgs e) 
     { 
       ThreadStart tStart = new ThreadStart(DoWorkDownload); 
       Thread thread = new Thread(tStart); 
       thread.SetApartmentState(ApartmentState.STA); 
       thread.Start(); 
     } 

     private void DoWorkDownload() 
     { 
      SaveFileDialog sfd = new SaveFileDialog(); 
      sfd.InitialDirectory = "C:\\"; 
      sfd.Filter = "All files (*.*)|*.*"; 
      sfd.FilterIndex = 1; 
      sfd.RestoreDirectory = true; 

      if (sfd.ShowDialog() == DialogResult.OK) 
      { 
      //do file saving here 
      } 
     } 
} 

Моя логика в приведенном выше коде: на кнопку мыши создать новую тему , передать метод DoWorkDownload() в поток, а затем запустить его; в этот момент предполагается ввести метод работы, однако при отладке он никогда не входит в DoWorkDownload().

Кто-нибудь знает, что мне не хватает?

спасибо.

+0

Основная тема приложения также была запущена в режиме STA? –

+0

Bogdan_Ch, это верно: мой код выше был написан в Form1.cs, а проект также включает Program.cs, который имеет [STAThread] для Main. Должен ли я использовать STA в моей декларации? –

ответ

2

Вы можете использовать BackgroundWorker, который прост в использовании.

Кроме того, я не уверен, что это полностью безопасно (я могу ошибаться), чтобы показать SaveFileDialog в новом потоке. Моя рекомендация будет представлять собой поток как таковой:

  1. Показать SaveFileDialog в основной теме.
  2. Передайте имя файла методу, который затем вызывается асинхронно.

Вот пример реализации, без использования BackgroundWorker:

private void button1_Click(object sender, EventArgs e) 
{ 
    SaveFileDialog sfd = new SaveFileDialog(); 
    sfd.InitialDirectory = "C:\\"; 
    sfd.Filter = "All files (*.*)|*.*"; 
    sfd.FilterIndex = 1; 
    sfd.RestoreDirectory = true; 
    if (sfd.ShowDialog() == DialogResult.OK) 
    { 
    // Invoke the SaveFile method on a new thread. 
    Action<string> invoker = new Action<string>(SaveFile); 
    invoker.BeginInvoke(sfd.FileName, OnSaveFileCompleted, invoker); 
    } 
} 

protected void SaveFile(string fileName) 
{ 
    // save file here (occurs on non-UI thread) 
} 

protected void OnSaveFileCompleted(IAsyncResult result) 
{ 
    Action<string> invoker = (Action<string>) result.AsyncState; 
    invoker.EndInvoke(result); 
    // perform other actions after the file has been saved (also occurs on non-UI thread) 
} 

Обратите внимание, что все действия, выполняемые на нитях без пользовательского интерфейса, должны влиять только на элементы, не UI. Если вы хотите изменить элементы пользовательского интерфейса, вы должны перевести вызов обратно в поток пользовательского интерфейса, используя Control.Invoke (например, this.Invoke). См. this post для получения дополнительной информации.

+0

В моем случае это работает либо с BackgroundWorker, либо с ThreadStart. –

+0

Благодарим вас за код, но что такое «Действие», это особый тип, который вы создали для этой цели? Не могли бы вы дать мне подсказку о том, как я могу это реализовать? –

+0

Я его не построил, нет. System.Action - это общий тип делегата в .NET, который используется для вызова методов, возвращающих _void_ и принимающих один параметр типа _T_, например. void SaveFile (string fileName), где _T_ в этом случае _string_. – bernhof

1

Возможно, Bernhof может быть прав, но будьте осторожны. Все элементы пользовательского интерфейса должны выполняться в одном потоке. Поэтому, если вы создаете новый поток для SFD, убедитесь, что вы не обновляете какой-либо элемент управления в своем главном окне.

С наилучшими пожеланиями, Гийом Hanique

1

В моем случае отладчик DO входит DoWorkDownload() он входит после окончания btnDownload_Click() установить точку останова на SaveFileDialog SFD = новый SaveFileDialog(); и он должен работать

Для того, чтобы доказать, что он работает в асинхронном режиме я даже поместить следующий код

ThreadStart tStart = new ThreadStart(DoWorkDownload); 
Thread thread = new Thread(tStart); 
thread.SetApartmentState(ApartmentState.STA); 
thread.Start(); 

Thread.Sleep(10000); 
MessageBox.Show("qwe"); 

и работать без отладчика, и вы увидите, что, когда текущий поток будет спать, SaveFileDialog появится. .. и только через 10 секунд окно сообщения будет показано

0

в классе

private object sync_temp = new object(); 

и в методе резьбы

SaveFileDialog save = new SaveFileDialog(); 
// your code to do with "save" 
Action ac =() => { lock (sync_temp) { save.ShowDialog(); } }; 
Invoke(ac); 
//Thread.Sleep(10); 
lock (sync_temp) 
{ 
    string path = save.FileName; 
} 
Смежные вопросы