不确定如何在线程之间传递对象

时间:2015-01-07 13:55:04

标签: c# wpf multithreading

我意识到我之前提过了一个非常类似的问题,但我的结构错了。我错误地认为我可以在Invoke中执行我的图标生成。这导致了一个不同的问题。

我有一个包含500个SVG的文件夹。我想在文件夹中创建每个SVG的对象。我需要在一个单独的线程上执行此操作,因为它可能需要一些时间才能完成,并且正在锁定UI。

private void Grid_Loaded(object sender, RoutedEventArgs e)
{
     Thread t = new Thread(LoadIcons);
     t.SetApartmentState(ApartmentState.STA);

     t.Start();
}

private void LoadIcons()
{
   //Populate ListOfSVGsInFolder

   Foreach(String SVGFile in ListOfSVGsInFolder)
   {
       Icon icon = new Icon

       //Perform ~50 lines of code which get the paths and other details from the
       //SVGFile and plug them into my icon object

       //Now I had a fully generated Icon

       //Add the icon to the form
       WrapPanel.Children.Add(icon)
   }
} 

我的问题是我无法将图标添加到WrapPanel。因为我希望这个代码在一个单独的线程上执行,所以我不能直接与UI交谈。但是,我可以这样做:

Foreach(String SVGFile in ListOfSVGsInFolder)
{         
    Icon icon = new Icon

    //Perform ~50 lines of code which get the paths and other details from the
    //SVGFile and plug them into my icon object

    Dispatcher.Invoke(new Action(() =>
    {         
      WrapPanel.Children.Add(icon);
    }));
}

但在这样做时,我现在无法在尝试将其添加到WrapPanel时访问我的图标对象。

基本上,我希望能够在文件夹中找到的SVG上执行所有这些计算,在同一个线程中创建SVG的对象,然后将这些对象添加到UI中。

3 个答案:

答案 0 :(得分:2)

Thread t = new Thread(LoadIcons); //Don't do this

一般情况下,不要创建线程来做后台工作。对于系统和您自己来说,正确管理它们需要做很多工作。而是使用ThreadPool。

最简单的方法是使用TaskFactory

foreach(string svgFile in listOfSVGsInFolder)
{
    Task.Run(() => // Task.Factory.StartNew for pre .net 4.5
      {
        Debug.WriteLine ("Creating SVG in thread {0}", Thread.CurrentThread.ManagedThreadId);

        Icon icon = // whatever you do to create it

        Application.Current.Dispatcher.BeginInvoke(
          DispatcherPriority.Background,
          () => {         
                  WrapPanel.Children.Add(icon);
                });
      });
}

答案 1 :(得分:2)

这就是BackgroundWorker

的原因
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
    BackgroundWorker bgWorker = new BackgroundWorker();
    bgWorker.DoWork += LoadIcons;
    bgWorker.ProgressChanged += IconDone;
    bgWorker.RunWorkerAsync();
}

private void IconDone(object sender, ProgressChangedEventArgs e)
{
    Icon icon = e.UserState as Icon;
    if (icon != null)
        WrapPanel.Children.Add(icon); //This code is executed in the GUI thread
}

private void LoadIcons(object sender, DoWorkEventArgs doWorkEventArgs)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    //Populate ListOfSVGsInFolder
    foreach (String SVGFile in ListOfSVGsInFolder)
    {
        Icon icon = new Icon

        //Perform ~50 lines of code which get the paths and other details from the
        //SVGFile and plug them into my icon object

        //Now I had a fully generated Icon


        worker.ReportProgress(0, icon);
    }
}

更多信息:MSDN

答案 2 :(得分:1)

您需要一个图标列表:

List<Icon> iconList = new List<Icon>();
在LoadIcons中

// ... build your icon here
lock(iconList)
{
    iconList.Add(icon);
}
你的UI线程中的

lock(iconList)
{
    icon = iconList[0];
}
// use the icon in the GUI

当然,如果列表中有内容,您必须检查UI线程,并删除“使用过的”#39;这个列表中的图标都在lock()