线程传递数据和窗口关闭

时间:2015-05-13 09:57:56

标签: c# wpf multithreading excel

我创建了一个简单的WPF项目,在按钮上单击我创建一个带有新窗口的单独线程,并将数据传递给它。在应用程序退出时,我试图安全地关闭该线程/窗口。但是,偶尔会出现波纹管异常,导致应用程序不稳定 所以我的问题是如何优雅地处理这种情况。 THX

在线:

Dispatcher.Invoke(new Action(() => 

我有

A first chance exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll  
Additional information: Thread was being aborted.

我的视图包含以下代码:

构造

public MyView(ConcurrentQueue<MyItem> actionReports, ManualResetEvent actionCompletedEvent, string actionName)
{
    _actionReports = actionReports;
    _actionCompletedEvent = actionCompletedEvent;
    _actionName = actionName;

    InitializeComponent();
    DataContext = this;

    this.Loaded += MyView_Loaded;
}

void MyView_Loaded(object sender, RoutedEventArgs e)
{
    var worker = new BackgroundWorker();
    worker.DoWork += (o, ea) =>
    {
        while (true)
        {
            if (_actionCompletedEvent.WaitOne(0))
            {
         // Issue
                Dispatcher.Invoke(new Action(() =>
                {
                    Close();
                }));

                Thread.Sleep(100);
            }

            while (!_actionReports.IsEmpty)
            {
                // Do some stuff
            }
        }
    };

    worker.RunWorkerAsync();
}

初始化窗口

public WindowLauncher(ManualResetEvent actionCompletedEvent, ManualResetEvent reportWindowClosedEvent, string actionName)
{
    _actionCompletedEvent = actionCompletedEvent;
    _reportWindowClosedEvent = reportWindowClosedEvent;
    _actionName = actionName;

    Thread thread = new Thread(new ThreadStart(() =>
    {
        _reportWindow = new MyView(_messageQueue, _actionCompletedEvent, actionName);
        _reportWindow.Show();

        // InvokeShutdown to terminate the thread properly
        _reportWindow.Closed += (sender, args) =>
        {
            _reportWindow.Dispatcher.InvokeShutdown();
        };
        _resetEvent.Set();
        Dispatcher.Run();
    }));

    thread.Name = "MyWindowThread";
    thread.SetApartmentState(ApartmentState.STA);
    thread.IsBackground = true;
    thread.Start();
}

2 个答案:

答案 0 :(得分:1)

我通常至少会尝试取消BackgroundWorker事件中的Window.OnClosing异步操作并捕获待处理的取消。您仍然需要注意ThreadAbortExceptions,但前提是您的异步​​进程长时间运行。

private BackgroundWorker _worker;

private void MyView_Loaded(object sender, RoutedEventArgs e)
{
    _worker = new BackgroundWorker();
    _worker.WorkerSupportsCancellation = true;
    _worker.DoWork += (o, ea) =>
    {
        while (true)
        {
            if (_actionCompletedEvent.WaitOne(0))
            {
                if (_worker.CancellationPending)
                {
                    ea.Cancel = true;
                    return;
                }

                // Issue
                Dispatcher.Invoke(new Action(() =>
                {
                    Close();
                }));

                Thread.Sleep(100);
            }

            while (!_actionReports.IsEmpty)
            {
                // Do some stuff
            }
        }
    };
}

protected override void OnClosing(CancelEventArgs e)
{
    _worker.CancelAsync();
}

答案 1 :(得分:0)

当您的应用退出时,运行时会自动中止后台线程。通常他们不会抛出ThreadAbortExceptions(见Foreground and Background threads

调用调度程序会导致在调度线程上运行方法,但由于您使用的是Invoke()而不是BeginInvoke(),因此调度程序需要通知后台线程该方法已完成。我怀疑这是引发异常的地方,但这只是我的猜想。

尝试捕获这样的异常:

try
{
    Dispatcher.Invoke(new Action(() =>
    {
         Close();
    }));
}
catch (ThreadAbortException)
{
    Thread.ResetAbort(); 
}

虽然如果在调度线程上引发异常,这可能无济于事。如果这不起作用,请尝试改为BeginInvoke()

顺便说一句,如果你在Invoked lambda的开头加入某种延迟并在那时关闭app,你可能会更容易重现这个bug。这意味着后台线程将在lambda完成时中止。