I am creating an instance of a class that is in DLL and can't be modified. It loads images and it takes long time which freezes the WinForms UI.
Can I instantiate the class on a new thread?
var images = new AppImages(); // This to execute on new thread?
var cboData = new List<string>();
foreach(var image in images)
{
cboData.Add(image);
}
comboBox.DataSource = cboData;
I am trying to use
private void My()
{
var images = ThreadPool.QueueUserWorkItem(GetAppImages);
var cboData = new List<string>();
foreach(var image in images)
{
cboData.Add(image);
}
comboBox.DataSource = cboData;
}
private AppImages GetAppImages()
{
return new AppImages();
}
but the threadPool doesn't return any value, it is just executing the code and I need the new instance to work with it later in the code.
Also, I can call the entire logic in a new thread because there are UI elements (the comboBox for example).
CodePudding user response:
I would suggest using Task.Run
to initialize AppImages
in a different thread, and await that task from the UI thread. So:
public async Task My()
{
Task<AppImages> task = Task.Run(() => new AppImages());
var images = await task;
comboBox.DataSource = images.Images.ToList();
}
The use of await
here means that the last line of the method still runs on the UI thread - but it won't block the UI while the task is running.
CodePudding user response:
You need to use Invoke
. This can be used by non-UI threads to access UI elements (via the UI thread). This is done because only the UI thread can interact with UI elements.
Here's an example of the creation of a new thread, and waiting for 10 seconds just to pretend it is doing work, but after waiting (e.g. when the results/images are ready), and we want to modify UI elements we use Invoke
.
private void button1_Click(object sender, EventArgs e) {
Task.Run(() => {
// load stuff that takes time: simulate by sleeping for 10 seconds
Thread.Sleep(10000);
var newText = "new button text";
// now we want to change something in the UI, we use Invoke.
this.Invoke(new Action(() => {
this.button1.Text = newText;
}));
});
}
CodePudding user response:
You can wrap this code in a method and can call that method using
System.Threading.Tasks.Task.Run()
eg
void LoadData()
{
var images = new AppImages(); // This to execute on new thread?
var cboData = new List<string>();
foreach(var image in images)
{
cboData.Add(image);
}
comboBox.DataSource = cboData;
}
and call it like this
Task.Run(() => LoadData());
Please refer the doc from Microsoft Task.Run Method