简体   繁体   English

带有BackgroundWorker的App.Xaml中的WPF CrossThreadException

[英]WPF CrossThreadException in App.Xaml with BackgroundWorker

I have this in my App.Xaml: 我的App.Xaml中有这个:

public App()
{
    _backgroundWorker = new BackgroundWorker();
    _backgroundWorker.DoWork += new DoWorkEventHandler(DoBackgroundWork);
    _backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundCompleted);
    _backgroundWorker.RunWorkerAsync();

    _splashView = new SplashView();
    _splashView.Show();
}

The DoBackgroundWork method performs some database setup, and then the BackgroundCompleted event closes the _splashView and shows _mainView . DoBackgroundWork方法执行一些数据库设置,然后BackgroundCompleted事件关闭_splashView并显示_mainView

However, modifying anything in the _splashView from BackgroundCompleted causes a cross thread exception, which is what I though background workers were designed to fix. 但是,从BackgroundCompleted修改_splashView任何内容_splashView导致跨线程异常,这是我设计了后台工作程序修复的。 I'm guessing this has something to do with the way backgroundworker's work in App.Xaml . 我猜想这与App.Xaml backgroundworker的工作方式App.Xaml Maybe this is a bad way to do a splash screen? 也许这是做启动画面的坏方法?

The background worker uses the SynchronizationContext. 后台工作者使用SynchronizationContext。 This is going from memory, but I don't think it has been initialised in the App constructor. 这是从内存中进行的,但我认为它尚未在App构造函数中初始化。

Before you construct the BW check SynchronizationContext.Current is not null. 在构造BW之前,请检查SynchronizationContext.Current不为null。 Also check SynchronizationContext.Current is the same before construction of BW and in the completed method. 还要在构造BW之前和完成的方法中检查SynchronizationContext.Current是否相同。

If it's not, you'll need to move the code later in the process... App.OnStartUp should be fine 如果不是,则需要在此过程中稍后移动代码... App.OnStartUp应该很好

Maybe this is a bad way to do a splash screen? 也许这是做启动画面的坏方法?

Unless I've misinterpreted your question, I don't think there's a need to do this to show a splash screen. 除非我对您的问题有误解,否则我认为不需要显示初始屏幕。 Just select the image and in the Properties window click the BuildAction dropdown and select SplashScreen . 只需选择图像,然后在“属性”窗口中单击BuildAction下拉列表,然后选择SplashScreen Also, I think you can simplify your process by eliminating the BackgroundWorker , unless your data function takes a long time. 另外,我认为您可以通过消除BackgroundWorker来简化流程,除非您的数据功能花费很长时间。 I believe you added it to accomodate the showing/hiding of the splash screen. 我相信您已添加它以适应初始屏幕的显示/隐藏。

There is no guarantee which thread the event handler of OnWorkCompleted will be used for execution. 无法保证OnWorkCompleted的事件处理程序将使用哪个线程执行。

See similar question BackgroundWorker OnWorkCompleted throws cross-thread exception 看到类似的问题BackgroundWorker OnWorkCompleted引发跨线程异常

You have to use the Invoke or BeginInvoke methods to modify visual elements from a background thread. 您必须使用InvokeBeginInvoke方法来修改后台线程中的视觉元素。 You can call this directly on the object whose properties you are modifying or use the Dispatcher . 您可以直接在要修改其属性的对象上调用此方法,也可以使用Dispatcher

EDIT: As per conversation with Adam 编辑:根据与亚当的对话

The SynchronizationContext has the desired effect for the OnWorkCompleted event handler to be run on the initial thread (not the BackgroundWorker's). 对于在初始线程(而不是BackgroundWorker的线程)上运行OnWorkCompleted事件处理程序, SynchronizationContext具有所需的效果。 http://msdn.microsoft.com/en-us/magazine/gg598924.aspx . http://msdn.microsoft.com/zh-CN/magazine/gg598924.aspx (See Figure 2) (见图2)

If the BackgroundWorker is created and run prior to the SynchronizationContext initialization, then the OnWorkCompleted will execute on possibly the same thread as the BackgroundWorker. 如果BackgroundWorker是在SynchronizationContext初始化之前创建并运行的,则OnWorkCompleted将在与BackgroundWorker相同的线程上执行。

Thanks Adam. 谢谢亚当。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM