How do I use this?
I am working on a program, that focuses on working with files and directories, and displaying information about the files in a DataGridView.. That and copying the files, are basically the two things it does.
Now when I am trying to 'scan' a list of 1-400 600mb-1.6gb isos, archives, etc. This becomes time consuming as I have to retrieve information specificic to each file to be displayed in the DataGridView. I have a Strongly typed datatype, Game, with properties, and I have everything functioning. I am just hitting a roadblock, or having a blonde moment. Delegates, callbacks, etc. all seem like Hieroglyphics to me. I am used to being around scary looking datatypes I have no Idea what to do with. But, when it comes time to actually harness one, and use it the right way.. yeah, no formal knowledge there.
This works..
private Task<IBindingList> getGamesTask(string folder)
{
string[] filters = new[] { "iso", "gcm" };
string[] files = GetFilesFolder(folder, filters, true).Result;
var source = new BindingSource();
IBindingList games = new BindingList<Game>();
for (int j = 0; j < files.Length; j )
{
var file = files[j];
games[j] = GetGameInfo(files[j]);
}
return FromResult(games);
}
I want to make it (I think...) this:
//Call from elsewhere
{
var progress = new Progress<int>(value => {
pbCopy.Value = i > pbCopy.Maximum ? pbCopy.Maximum : i;
}});
await Task.Run(() = getGamesTask(folder, progress));
}
private Task<IBindingList> getGamesTask(string folder, IProgress<int> i)
{
string[] filters = new[] { "iso", "gcm" };
string[] files = GetFilesFolder(folder, filters, true).Result;
var source = new BindingSource();
IBindingList games = new BindingList<Game>();
for (int j = 0; j < files.Length; j )
{
var file = files[j];
games[j] = GetGameInfo(files[j]);
i?.Report(j);
}
return FromResult(games);
}
Taken from:
This Stack Question
var progress = new Progress<int>(value => { progressBar.Value = value; });
await Task.Run(() => GenerateAsync(progress));
void GenerateAsync(IProgress<int> progress)
{
...
progress?.Report(13);
...
}
So, every iteration, i?.Report(j) should hit the progress bar and update it. right?.. It compiles, but I can't get it to .. well. actually work or update the progress bar. I'm in new territory, and honestly, have very little to no clue where to go from here. Trying to get further into Asynchronous programming, threading, etc. at least learn some new things.. but.. the right way, not just, huh that worked. cool. Only for someone who knows what their doing to loose their mind because you did it that way.
Question re-asked: How do I get this code, or similar code to hit my Progress bar on each iteration with an int?
Andy's first answer was valid. This works, it just isn't running on the UI thread. So .. And I lost the comment/snippet, you have to check if invoke is required, and use progressBar.BeginInvoke.
@Andy if you could re-add that snippet, It's more than likely what others are looking for. It was what I was.. and.. its gone now :P
CodePudding user response:
I am going to go out on a limb here and assume you aren't on the UI thread.
Try changing this line:
var progress = new Progress<int>(value => { progressBar.Value = value; });
to this:
var progress = new Progress<int>(value =>
{
// are we outside the UI thread?
if (progressBar.InvokeRequired)
{
// yes we are, post it to the UI thread to process
progressBar.Invoke(new Action(() => progressBar.Value = value));
return;
}
// no we aren't. We are in the UI thread. Execute it now.
progressBar.Value = value;
});
Any time you modify the UI, it must be done from the UI thread. Calling Invoke
on any Control
will execute the delegate
(in this case, an Action
) on said UI thread. The InvokeRequired
checks to see if you are currently executing from the UI thread.
The reason I believe this is what's happening is you are working with Task
... Those could execute outside the UI context.