2013-04-22 25 views
1

我想要使用WPF窗口而不是常规Windows.MessageBox,主要是因为我希望它具有“详细信息”框以显示错误。这工作正常,直到我开始进入线程。从任务中的Catch语句显示自定义弹出窗口

我想运行一个任务,该任务将获取SQL Server数据库中可能需要一段时间的表的列表。如果出现错误 - 比如尝试连接时发生超时 - 我想显示带有例外细节的自定义弹出窗口。

在拳头,它不断崩溃。经过一些阅读之后(对你们来说),我发现Task不在UI线程中,并且不能显示一个窗口(原生的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

我认为最好的方法是在应用程序的主UI线程上显示窗口。

您可以通过将Dispatcher传递给DoWork()来实现。但是分开执行计算和显示错误的顾虑也是有意义的。所以,你可以做的是让DoWork()抛出并处理异常,继续Task。只有当出现错误时,将继续运行,将在主UI线程的上下文中运行:

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 2013-04-22 21:51:14