2015-01-07 47 views
1

我意识到我之前问过一个非常类似的问题,但是我的结构是错误的。我错误地认为我可以在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中。

+1

你需要的数据结构(列表/堆栈/ fifo),它由一个线程写入并由另一个线程读取。在访问它之前,你需要锁定()这个结构。 – DrKoch

+0

@DrKoch感谢您的评论。你有任何链接到这个正在申请?我对线程很陌生。 – Ralt

+0

查看更完整的答案 – DrKoch

回答

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

或.NET 4.5的Task.Run – sondergard

+0

似乎是最有用的,我还没有得到它的工作。由于某种原因,现在每次都会创建一个线程,foreach循环会超出范围。将不得不研究它 – Ralt

+0

@Ralt我的代码不会创建任何线程。你是什​​么意思超出范围?也许更新你的问题。 – weston

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线程中,如果列表中有东西,并从该列表中删除'used'图标,则全部在锁()内()

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

+0

我得到'调用线程必须是STA,因为很多UI组件都需要这个。'当试图在LoadIcons中创建我的新图标 – Ralt

+0

哦,您使用的是什么样的UI元素? –