2015-01-07 2 views
1

Я понял, что раньше задавал очень похожий вопрос, однако моя структура была неправильной. Я ошибался, думая, что смогу выполнить свое создание иконок в Invoke. Это привело к другой проблеме.Не уверен, как пройти объект между потоками

У меня есть папка с 500 SVG. Я хочу создавать объекты каждого SVG в папке. Мне нужно сделать это на отдельном потоке, так как это может занять некоторое время и блокирует пользовательский интерфейс.

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. Поскольку я хочу, чтобы этот код выполнялся в отдельном потоке, я не могу напрямую разговаривать с пользовательским интерфейсом. Тем не менее, я мог бы сделать:

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 в одном потоке, а затем добавлять эти объекты в пользовательский интерфейс.

+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

Или Task.Run от .NET 4.5 – 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 

, конечно, вы должны проверить в потоке пользовательского интерфейса, если в списке есть что-то, и удалить из этого списка «используемые» значки, все внутри блокировки()

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, потому что для этого требуется множество компонентов пользовательского интерфейса.'при попытке создать мой новый значок внутри LoadIcons – Ralt

+0

О, какие элементы пользовательского интерфейса вы используете? –

Смежные вопросы