Reputation: 2166
I realised I asked a very similar question earlier, however my structure was wrong. I was wrong in thinking I could perform my icon generation in the Invoke. This has lead to a different problem.
I have a folder with 500 SVG's in. I want to create objects of each SVG in the folder. I need to do this on a seperate thread as it can take a some time to complete, and is locking the 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)
}
}
My problem is that I cannot add the icons to the the WrapPanel. As I want this code to be carried out on a seperate thread, I can't talk directly to the UI. However, I could do:
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);
}));
}
but in doing so, I can now no longer access my icon object when trying to add it to the WrapPanel.
Basically, I want to be able to perform all of these calculations on the SVGs found in the folder, create objects of the SVGs in the same thread, and then add these object to the UI.
Upvotes: 1
Views: 328
Reputation: 53
That's why there are 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);
}
}
more info : MSDN
Upvotes: 2
Reputation: 54791
Thread t = new Thread(LoadIcons); //Don't do this
In general don't create threads to do background work. It's a lot of work for both the system and yourself to manage them properly. Instead use a ThreadPool.
The easiest way is to use a 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);
});
});
}
Upvotes: 2
Reputation: 9772
You'll need a list of Icons:
List<Icon> iconList = new List<Icon>();
in LoadIcons:
// ... build your icon here
lock(iconList)
{
iconList.Add(icon);
}
in your UI thread:
lock(iconList)
{
icon = iconList[0];
}
// use the icon in the GUI
of course you'll have to check in the UI thread if there is something in the list and remove 'used' icons from this list, all inside the lock()
Upvotes: 1