【问题标题】:BackgroundWOrker Invalid cross-thread access [closed]BackgroundWOrker 无效的跨线程访问[关闭]
【发布时间】:2013-04-08 14:07:26
【问题描述】:

我尝试在另一个线程上添加加载数据模型并将项目加载到列表框,因为将 50 个项目加载到列表框需要很长时间(大约 5 秒)。

BackgroundWorker 有问题,它显示错误无效的跨线程访问

他是 Inbox.xaml 的代码

    public Inbox()
    {
        InitializeComponent();

        DataContext = App.ViewModel;
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        ProgressIndicator progress = new ProgressIndicator
        {
            IsVisible = true,
            IsIndeterminate = true,
            Text = "Načítání"
        };

        SystemTray.SetProgressIndicator(this, progress);
        SystemTray.IsVisible = true;

        BackgroundWorker backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
        backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);

        backgroundWorker.RunWorkerAsync();
    }

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        LoadData();
    }

    void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            MessageBox.Show(e.Error.Message);
        }
        else
        {
            SystemTray.IsVisible = false;
        }
    }

    private void LoadData()
    {
        try
        {
            (this.DataContext as MainViewModel).LoadInboxData();
        }
        finally
        {
            TasksListBox.ItemsSource = (this.DataContext as MainViewModel).Tasks;
        }
    }

我做错了什么?

【问题讨论】:

  • 您遇到什么错误?你能发布堆栈跟踪吗?
  • 猜测是您的LoadData,因为它正在访问 UI 控件的ItemsSource。我想你需要调用Dispatcher,虽然我记不清了。
  • 您可以在此处和其他网站上搜索数以千计的问题之一。这是一个一天要问好几次的问题……看看屏幕一侧的Related 线程。

标签: c# multithreading silverlight windows-phone-7 xaml


【解决方案1】:

BackgroundWorker.DoWork 处理程序在后台非 ui 线程上运行。在您的示例中,LoadData() 方法在后台非 ui 线程上运行,并且您正在该方法中设置 ListBox 的 ItemSource 属性。

您应该尝试将该代码移至您的 BackgroundWorkder.RunWorkerCompleted 处理程序,因为此处理程序在 UI 线程上运行。

您的代码可以像下面这样重写以避免错误:

void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Error != null)
    {
        MessageBox.Show(e.Error.Message);
    }
    else
    {
        SystemTray.IsVisible = false;
    TasksListBox.ItemsSource = (this.DataContext as MainViewModel).Tasks;
    }
}

private void LoadData()
{
    (this.DataContext as MainViewModel).LoadInboxData();
}

【讨论】:

  • 当我从代码中删除loadinboxdata()行时出现同样的错误,我需要在项目添加到列表框时显示加载,这需要很长时间
  • 如果您要覆盖“正在加载”横幅,有多种方法可以实现 1) 拥有另一个控件,例如边框/文本块/进度条,然后按 z 顺序显示在 ListBox 顶部并根据需要切换该控件的可见性。 2) 用户装饰器控制。参考这个codeproject.com/Articles/57984/WPF-Loading-Wait-Adorner
【解决方案2】:

您正在尝试从非 UI 线程更新 UI,因此您会收到异常。

只有 UI 线程可以执行 UI 更新,您需要使用 Dispatcher 才能从非 UI 线程更新 UI。

Dispatcher.BeginInvoke(() =>
{
   // Update UI in here as this part will run on the UI thread.
});

见:http://msdn.microsoft.com/en-gb/library/system.windows.threading.dispatcher.begininvoke.aspx

【讨论】:

  • 使用后台工作人员的全部意义在于您无需手动调用。他应该简单地使用工作人员完成事件中的结果而不是工作事件中的结果来更新 UI。
  • 好的,但我需要在项目添加到列表框时显示加载,这需要很长时间
  • @Servy 他确实可以!这将是一种方法,但是,如果他需要在长时间运行的操作之间更新 UI,那么调度调用是可行的方法,除非他创建多个后台工作人员并将它们链接在一起 - 混乱!更好的更“现代”的方法是简单地移交给一个新的异步方法,并让异步等待,将长操作强制到新线程上来处理所有的链接和繁重的工作。
  • @Clint 即使有 BGW,它仍然非常简单。您可以简单地使用进度报告机制来使用长时间运行的操作的进度更新 UI。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
相关资源
最近更新 更多