【问题标题】:Sharing List<T> with BackgroundWorker across two forms跨两种形式与 BackgroundWorker 共享 List<T>
【发布时间】:2013-11-19 21:25:44
【问题描述】:

我正在尝试构建一个小的图像小部件。它应该以启动画面启动,从 XML 列表加载图像,将它们放入对象内的列表中,然后关闭该表单并返回到 MainWindow。我在初始屏幕上使用了 BackgroundWorker,因此我可以根据需要退出。

据我所知,启动画面正在工作,至少列表的 Count 在 MainWindow 检查时显示其中包含对象。我遇到的问题是当我尝试访问列表中的对象时。然后我收到以下错误:调用线程无法访问此对象,因为另一个线程拥有它。

我已经尝试过 Delegates,一个静态对象,甚至将 MainWindow 的副本传递到 Splash 表单(这是我正在粘贴的版本)。但是,我无法解决这个问题。欢迎任何帮助。

Splash.xaml.cs

namespace Yvonne1
{
    public partial class Splash : Window
    {
        public BackgroundWorker bw;
        public string url = @"http://domain.com/pics-list.php";
        public MainWindow mw;
        public XmlNodeList xl;
        public Splash()
        {
            InitializeComponent();
            SetupWorker();
            FetchXml();
            progOne.Maximum = xl.Count;
            bw.RunWorkerAsync();
        }

        private void SetupWorker()
        {
            bw = new BackgroundWorker();
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = true;
        }

        private void FetchXml()
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(this.url);
                this.xl = doc.SelectNodes("//image");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                this.DialogResult = false;
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            bw.CancelAsync();
            this.DialogResult = false;
        }

        public void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            int xcount = 0;
            foreach(XmlNode xn in xl)
            {
                string full = xn.FirstChild.InnerText;
                string thumb = xn.LastChild.InnerText;
                BitmapImage temp = new BitmapImage(new Uri(thumb));
                mw.p1.New = new Piccy(full, thumb, temp);

                xcount += 1;
                bw.ReportProgress(xcount);

                Thread.Sleep(200);
                if (bw.CancellationPending == true)
                {
                    e.Cancel = true; return;
                }
            }
        }

        public void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progOne.Value = Double.Parse(e.ProgressPercentage.ToString());
            int done = int.Parse(progOne.Value.ToString()) - 1;
            Piccy temp = mw.p1.Get(done);
            txtStatus.Text = "Fetched: " + temp.Thumb;
        }

        public void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (progOne.Value == progOne.Maximum)
            {
                this.DialogResult = true;
            }
        }
    }
}

MainWindow.xaml.cs(有错误的部分。)

private void StartUp()
{
    try
    {
        MessageBox.Show(p1.Count.ToString());
        Piccy temp = p1.Get(1);
        imgMain.Source = temp.Img;
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message+"\n\n"+ex.Source+"\n\n"+ex.StackTrace, "Error");
    }
}

imgMain.Source = temp.Img; 行是线程错误出现的地方。

提前致谢。

更新:BitmapImage temp = new BitmapImage(new Uri(thumb)); 行是问题所在。谢谢。

【问题讨论】:

  • google.com.au/…的可能重复
  • TLDR; ta.speot.is 链接,除非您使用 FromCurrentSynchronizationContext,否则您无法在后台线程中更改绑定在 UI 线程上的集合
  • 并且BitmapImage绑定到UI线程。我才意识到这一点。

标签: c# wpf multithreading backgroundworker


【解决方案1】:

试试这个,希望能解决你的问题

private void StartUp()
{
 try
 {
    MessageBox.Show(p1.Count.ToString());
    Piccy temp = p1.Get(1);
    this.Dispatcher.Invoke((Action)(()=>imgMain.Source = temp.Img);
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message+"\n\n"+ex.Source+"\n\n"+ex.StackTrace, "Error");
  }

}

【讨论】:

  • 晚了一年,但我才看到这个答案。谢谢你。我选择了一个匿名代表(lambda?)。
【解决方案2】:

您可以添加一个 Singleton 类,该类将包含一个公共列表。使用单例的优点是类/对象总是有一个实例(以及列表),并且每个类或线程都可以获得该单例类的实例。如果实现正确,这意味着您可以从程序中的每个类和线程访问此 Singleton 中的所有变量和方法。 阅读更多内容并了解如何实现它:http://msdn.microsoft.com/en-us/library/ff650316.aspxhttp://msdn.microsoft.com/en-us/library/ff650849.aspx

【讨论】:

    猜你喜欢
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 2013-02-26
    • 1970-01-01
    • 2013-06-28
    相关资源
    最近更新 更多