2015-01-07 78 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元素? –