WPF使用和访问BackgroundWorker线程中的ObjectContext

时间:2013-01-16 13:43:15

标签: wpf multithreading backgroundworker invoke ui-thread

我有一个类似下面的代码(为了便于阅读,我删除了一些代码)

    private void RicercaArticoloStripped(object sender, DoWorkEventArgs e)
    {
        try
        {
            using (var context = new ControlloSchedeLocalEntities())
            {
                var prodotti = context.VProdotti.Where(i => i.WACMAT == textBoxCodiceArticolo.Text);

                if (prodotti.Count() > 0)
                {
                    this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(delegate()
                    {
                        textBlockDescrizioneArticolo.Text = prodotti.FirstOrDefault().WADESC;
                    }));
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("Error:\n\n" + ex.Message + "\r\nStack: " + ex.ToString());
        }
    }


    private void textBoxCodiceArticolo_KeyUpStripped(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            worker = new BackgroundWorker();
            worker.WorkerReportsProgress = true;
            worker.DoWork += new DoWorkEventHandler(RicercaArticoloStripped);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RicercaArticoloWorkerCompleted);
            worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);

            object[] parameters = new object[] { textBoxCodiceArticolo.Text, textBlockDescrizioneArticolo.Text };
            worker.RunWorkerAsync(parameters);
        }
    }

所以,至于我对BackgroundWorker的理解,当我实例化时: var prodotti = context.VProdotti.Where(i => i.WACMAT == textBoxCodiceArticolo.Text);

我是从工作线程而不是UI线程做的。

但是当我尝试访问该值时,我在下面的行上遇到异常: if(prodotti.Count()> 0)

我得到(in)着名的错误: “调用线程无法访问此对象,因为其他线程拥有它”

为什么?

2 个答案:

答案 0 :(得分:0)

如前所述,您必须使用Dispatcher.BeginInvoke/Invoke从控件的所有者线程执行操作,否则您将获得“调用线程无法访问此对象,因为另一个线程拥有它”异常。这就是你得到这个例外的原因;

这就是为什么你在下面这行(调用prodotti.Count()时)得到这个例外的原因:

创建prodotti变量时,它只是一个IEnumerable<T>对象。所以他实际上只在你调用prodotti.Count()方法时进行计算,这就是为什么你在这一行上得到例外。

IEnumerable实际上是生成器,这意味着他每次使用时都会生成新的对象集。

要测试此项,您可以计算prodotti,如下所示:

var prodotti = context.VProdotti.Where(i => i.WACMAT == textBoxCodiceArticolo.Text).ToList();

在这种情况下,您将立即获得异常,因为.ToList()会强制进行所有计算。

查看本文中的生成器和枚举器:http://www.codeproject.com/Articles/155462/IEnumerable-Lazy-and-Dangerous

更新: 实际上,当您使用IEnumerable与引用类型时,您可以获得与以前相同的对象。请阅读以下答案:https://stackoverflow.com/a/14361094/1467309

答案 1 :(得分:0)

Text的属性TextBox获取DependencyProperty Text的值,这只能通过UI线程完成。您正在从工作线程访问textBoxCodiceArticolo.Text