2013-04-22 2 views
1

У меня есть окно WPF, которое я хочу использовать вместо обычного Windows.MessageBox, главным образом потому, что я хочу, чтобы у него было окно «Подробности», чтобы показать кишки ошибка. Это прекрасно работает, пока я не начну встраивать потоки.Показывать пользовательское всплывающее окно из оператора Catch внутри задачи

Я хочу запустить задачу, которая получит список, например, Таблицы в базе данных SQL Server, которые могут занять некоторое время. Если есть ошибка - скажем, время ожидания при попытке подключения - я хочу показать пользовательское всплывающее окно с подробными сведениями об исключении.

В кулак он продолжает падать. После некоторого чтения (что вам, ребята, здесь, на SO), мне стало ясно, что задача не была в потоке пользовательского интерфейса и не может показать окно (родной MessageBox все еще работает, похоже). Итак, я придумал следующее:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     Task t = Task.Factory.StartNew(() => DoWork()); 
    } 

    void DoWork() 
    { 
     Thread thread = new Thread(() => 
     { 
      Window1 popup = new Window1(); 
      popup.Show(); 
      System.Windows.Threading.Dispatcher.Run(); 
     }); 

     thread.SetApartmentState(ApartmentState.STA); 
     thread.Start(); 
    } 
} 

Это температура приложение, которое я сделал, чтобы я мог продемонстрировать основы того, что я делаю. В основном приложении я отправляю исключение в качестве аргумента во всплывающее окно.

Мой вопрос заключается в следующем: это лучший способ сделать это? Кажется, он работает нормально, но не был на 100% уверен, что это была лучшая практика для смешивания нитей, подобных этому, и я подумал, что я поместил бы его там.

Если это хорошее решение, моим следующим вопросом будет вопрос о том, как связать всплывающее окно с родительским окном, чтобы у пользователя не было возможности закрыть родителя, пока всплывающее окно открыто, или всплывающее окно автоматически закрывается при закрытии родителя? Сам родитель не будет основным приложением.

ответ

4

Я думаю, что лучший способ сделать это - показать окно в главном потоке пользовательского интерфейса вашего приложения.

Вы можете сделать это, пройдя Dispatcher до DoWork(). Но также имеет смысл отделить проблемы выполнения расчета и отображения ошибки. Итак, что вы можете сделать, это позволить DoWork() выдать и обработать исключение в продолжении Task. Продолжение будет работать только тогда, когда происходит ошибка и будет выполняться в контексте главного потока пользовательского интерфейса:

private void button1_Click(object sender, RoutedEventArgs e) 
{ 
    Task.Factory.StartNew(DoWork) 
     .ContinueWith(
      task => ErrorBox.Show(task.Exception), 
      CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, 
      TaskScheduler.FromCurrentSynchronizationContext()); 
} 

private void DoWork() 
{ 
    throw new Exception(); 
} 

(Предполагая, что ErrorBox.Show() создает и показывает окно.)

+0

Красивая! Это сработало отлично. Ключом был задание TaskScheduler. Спасибо за помощь!! Только странная вещь, которую я имею сейчас, заключается в том, что если я поставлю точку останова прямо перед .Show() всплывающего окна, а затем нажимаю дальше, она блокирует программу, но без точки останова она работает нормально. Кажется, проблема с моим всплывающим окном, поэтому я должен изучить его. – Ernie

Смежные вопросы